Title: [246644] trunk
Revision
246644
Author
you...@apple.com
Date
2019-06-20 11:55:32 -0700 (Thu, 20 Jun 2019)

Log Message

Changing settings of a MediaStreamTrack clone should not alter the settings of the original track
https://bugs.webkit.org/show_bug.cgi?id=198840

Reviewed by Eric Carlson.

Source/WebCore:

Rename RealtimeVideoSource in RealtimeVideoCaptureSource.
Introduce RealtimeVideoSource as a class wrapping RealtimeVideoCaptureSource.
Its goal is to be able to have independent settings from its underlying RealtimeVideoCaptureSource.
It can also adapt size based on its settings if different than its RealtimeVideoCaptureSource.
Apply this wrapping for AV video sources as well as mock video sources.
Test: fast/mediastream/mediastreamtrack-video-clone.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/mediastream/MediaStreamTrackPrivate.cpp:
(WebCore::MediaStreamTrackPrivate::clone):
* platform/mediastream/RealtimeMediaSource.h:
* platform/mediastream/RealtimeVideoCaptureSource.cpp: Added.
(WebCore::RealtimeVideoCaptureSource::RealtimeVideoCaptureSource):
(WebCore::RealtimeVideoCaptureSource::~RealtimeVideoCaptureSource):
(WebCore::RealtimeVideoCaptureSource::prepareToProduceData):
(WebCore::RealtimeVideoCaptureSource::presets):
(WebCore::RealtimeVideoCaptureSource::setSupportedPresets):
(WebCore::RealtimeVideoCaptureSource::standardVideoSizes):
(WebCore::updateMinMax):
(WebCore::RealtimeVideoCaptureSource::updateCapabilities):
(WebCore::RealtimeVideoCaptureSource::supportsSizeAndFrameRate):
(WebCore::RealtimeVideoCaptureSource::frameRateRangeIncludesRate):
(WebCore::RealtimeVideoCaptureSource::presetSupportsFrameRate):
(WebCore::RealtimeVideoCaptureSource::supportsCaptureSize):
(WebCore::RealtimeVideoCaptureSource::shouldUsePreset):
(WebCore::RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate):
(WebCore::RealtimeVideoCaptureSource::setSizeAndFrameRate):
(WebCore::RealtimeVideoCaptureSource::adaptVideoSample):
(WebCore::RealtimeVideoCaptureSource::dispatchMediaSampleToObservers):
(WebCore::RealtimeVideoCaptureSource::clientUpdatedSizeAndFrameRate):
(WebCore::SizeAndFrameRate::toJSONObject const):
(WebCore::SizeAndFrameRate::toJSONString const):
* platform/mediastream/RealtimeVideoCaptureSource.h: Added.
(WebCore::RealtimeVideoCaptureSource::sampleRotation const):
(WebCore::RealtimeVideoCaptureSource::prefersPreset):
(WebCore::RealtimeVideoCaptureSource::setFrameRateWithPreset):
(WebCore::RealtimeVideoCaptureSource::canResizeVideoFrames const):
(WebCore::RealtimeVideoCaptureSource::setDefaultSize):
(WebCore::RealtimeVideoCaptureSource::observedFrameRate const):
(WTF::LogArgument<WebCore::SizeAndFrameRate>::toString):
* platform/mediastream/RealtimeVideoSource.cpp:
(WebCore::RealtimeVideoSource::RealtimeVideoSource):
(WebCore::m_source):
(WebCore::RealtimeVideoSource::~RealtimeVideoSource):
(WebCore::RealtimeVideoSource::startProducingData):
(WebCore::RealtimeVideoSource::stopProducingData):
(WebCore::RealtimeVideoSource::supportsSizeAndFrameRate):
(WebCore::RealtimeVideoSource::setSizeAndFrameRate):
(WebCore::RealtimeVideoSource::sourceMutedChanged):
(WebCore::RealtimeVideoSource::sourceSettingsChanged):
(WebCore::RealtimeVideoSource::preventSourceFromStopping):
(WebCore::RealtimeVideoSource::sourceStopped):
(WebCore::RealtimeVideoSource::videoSampleAvailable):
(WebCore::RealtimeVideoSource::clone):
* platform/mediastream/RealtimeVideoSource.h:
* platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp:
(WebCore::GStreamerVideoCaptureSource::GStreamerVideoCaptureSource):
* platform/mediastream/gstreamer/GStreamerVideoCaptureSource.h:
* platform/mediastream/mac/AVVideoCaptureSource.h:
* platform/mediastream/mac/AVVideoCaptureSource.mm:
(WebCore::AVVideoCaptureSource::create):
(WebCore::AVVideoCaptureSource::AVVideoCaptureSource):
* platform/mediastream/mac/MockRealtimeVideoSourceMac.h:
* platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
(WebCore::MockRealtimeVideoSource::create):
* platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::create):
(WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):
(WebCore::MockRealtimeVideoSource::supportsSizeAndFrameRate):
(WebCore::MockRealtimeVideoSource::setSizeAndFrameRate):
* platform/mock/MockRealtimeVideoSource.h:

LayoutTests:

* fast/mediastream/mediastreamtrack-video-clone-expected.txt: Added.
* fast/mediastream/mediastreamtrack-video-clone.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246643 => 246644)


--- trunk/LayoutTests/ChangeLog	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/LayoutTests/ChangeLog	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1,3 +1,13 @@
+2019-06-20  Youenn Fablet  <you...@apple.com>
+
+        Changing settings of a MediaStreamTrack clone should not alter the settings of the original track
+        https://bugs.webkit.org/show_bug.cgi?id=198840
+
+        Reviewed by Eric Carlson.
+
+        * fast/mediastream/mediastreamtrack-video-clone-expected.txt: Added.
+        * fast/mediastream/mediastreamtrack-video-clone.html: Added.
+
 2019-06-20  Russell Epstein  <russel...@apple.com>
 
         Layout Test imported/blink/fast/css/user-select-none.html is flaky.

Added: trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone-expected.txt (0 => 246644)


--- trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone-expected.txt	2019-06-20 18:55:32 UTC (rev 246644)
@@ -0,0 +1,12 @@
+   
+
+PASS Setup for width test 
+PASS Setup for height test 
+PASS Setup for width+height test 
+PASS Check cloned track settings after applying width constraints 
+PASS Check cloned track settings after applying width constraint to original track 
+PASS Check cloned track settings after applying height constraints 
+PASS Check cloned track settings after applying height constraints to original track 
+PASS Check cloned track settings after applying width+height constraints 
+PASS Check cloned track settings after applying width+height constraints to original track 
+

Added: trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone.html (0 => 246644)


--- trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediastream/mediastreamtrack-video-clone.html	2019-06-20 18:55:32 UTC (rev 246644)
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Clone a video track.</title>
+    <script src=""
+    <script src=""
+</head>
+<body>
+    <video id='video1' autoplay playsinline></video>
+    <video id='video2' autoplay playsinline></video>
+    <video id='video3' autoplay playsinline></video>
+    <script>
+    promise_test(async (t) => {
+        const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 160 } });
+        const streamClone = stream.clone();
+
+        video1.srcObject = stream;
+        video2.srcObject = streamClone;
+
+        const videoTrack = stream.getVideoTracks()[0];
+        const videoTrackClone = streamClone.getVideoTracks()[0];
+
+        assert_equals(videoTrack.enabled, videoTrackClone.enabled);
+        videoTrack.enabled = false;
+        assert_true(videoTrackClone.enabled);
+        videoTrack.enabled = true;
+
+        await videoTrackClone.applyConstraints({width: 640});
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().width, 640);
+            assert_equals(videoTrack.getSettings().width, 160);
+        }, "Check cloned track settings after applying width constraints");
+
+        const videoTrackClone2 = videoTrackClone.clone();
+        await videoTrackClone.applyConstraints({width: 1280});
+        video3.srcObject = new MediaStream([videoTrackClone2]);
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().width, 1280);
+            assert_equals(videoTrackClone2.getSettings().width, 640);
+        }, "Check cloned track settings after applying width constraint to original track");
+    }, "Setup for width test");
+
+    promise_test(async (t) => {
+        const stream = await navigator.mediaDevices.getUserMedia({ video: { height: 100 } });
+        const streamClone = stream.clone();
+
+        video1.srcObject = stream;
+        video2.srcObject = streamClone;
+
+        const videoTrack = stream.getVideoTracks()[0];
+        const videoTrackClone = streamClone.getVideoTracks()[0];
+
+        assert_equals(videoTrack.enabled, videoTrackClone.enabled);
+        videoTrack.enabled = false;
+        assert_true(videoTrackClone.enabled);
+        videoTrack.enabled = true;
+
+        await videoTrackClone.applyConstraints({height: 200});
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().height, 200);
+            assert_equals(videoTrack.getSettings().height, 100);
+        }, "Check cloned track settings after applying height constraints");
+
+        const videoTrackClone2 = videoTrackClone.clone();
+        await videoTrackClone.applyConstraints({height: 400});
+        video3.srcObject = new MediaStream([videoTrackClone2]);
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().height, 400);
+            assert_equals(videoTrackClone2.getSettings().height, 200);
+        }, "Check cloned track settings after applying height constraints to original track");
+    }, "Setup for height test");
+
+    promise_test(async (t) => {
+        const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 100, height: 100 } });
+        const streamClone = stream.clone();
+
+        video1.srcObject = stream;
+        video2.srcObject = streamClone;
+
+        const videoTrack = stream.getVideoTracks()[0];
+        const videoTrackClone = streamClone.getVideoTracks()[0];
+
+        assert_equals(videoTrack.enabled, videoTrackClone.enabled);
+        videoTrack.enabled = false;
+        assert_true(videoTrackClone.enabled);
+        videoTrack.enabled = true;
+
+        await videoTrackClone.applyConstraints({width: 100, height: 200});
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().width, 100);
+            assert_equals(videoTrackClone.getSettings().height, 200);
+            assert_equals(videoTrack.getSettings().height, 100);
+            assert_equals(videoTrack.getSettings().width, 100);
+        }, "Check cloned track settings after applying width+height constraints");
+
+        const videoTrackClone2 = videoTrackClone.clone();
+        await videoTrackClone.applyConstraints({width: 400, height: 200});
+        video3.srcObject = new MediaStream([videoTrackClone2]);
+        test(() => {
+            assert_equals(videoTrackClone.getSettings().width, 400);
+            assert_equals(videoTrackClone.getSettings().height, 200);
+            assert_equals(videoTrackClone2.getSettings().width, 100);
+            assert_equals(videoTrackClone2.getSettings().height, 200);
+        }, "Check cloned track settings after applying width+height constraints to original track");
+    }, "Setup for width+height test");
+
+    </script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (246643 => 246644)


--- trunk/Source/WebCore/ChangeLog	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/ChangeLog	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1,3 +1,83 @@
+2019-06-20  Youenn Fablet  <you...@apple.com>
+
+        Changing settings of a MediaStreamTrack clone should not alter the settings of the original track
+        https://bugs.webkit.org/show_bug.cgi?id=198840
+
+        Reviewed by Eric Carlson.
+
+        Rename RealtimeVideoSource in RealtimeVideoCaptureSource.
+        Introduce RealtimeVideoSource as a class wrapping RealtimeVideoCaptureSource.
+        Its goal is to be able to have independent settings from its underlying RealtimeVideoCaptureSource.
+        It can also adapt size based on its settings if different than its RealtimeVideoCaptureSource.
+        Apply this wrapping for AV video sources as well as mock video sources.
+        Test: fast/mediastream/mediastreamtrack-video-clone.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/mediastream/MediaStreamTrackPrivate.cpp:
+        (WebCore::MediaStreamTrackPrivate::clone):
+        * platform/mediastream/RealtimeMediaSource.h:
+        * platform/mediastream/RealtimeVideoCaptureSource.cpp: Added.
+        (WebCore::RealtimeVideoCaptureSource::RealtimeVideoCaptureSource):
+        (WebCore::RealtimeVideoCaptureSource::~RealtimeVideoCaptureSource):
+        (WebCore::RealtimeVideoCaptureSource::prepareToProduceData):
+        (WebCore::RealtimeVideoCaptureSource::presets):
+        (WebCore::RealtimeVideoCaptureSource::setSupportedPresets):
+        (WebCore::RealtimeVideoCaptureSource::standardVideoSizes):
+        (WebCore::updateMinMax):
+        (WebCore::RealtimeVideoCaptureSource::updateCapabilities):
+        (WebCore::RealtimeVideoCaptureSource::supportsSizeAndFrameRate):
+        (WebCore::RealtimeVideoCaptureSource::frameRateRangeIncludesRate):
+        (WebCore::RealtimeVideoCaptureSource::presetSupportsFrameRate):
+        (WebCore::RealtimeVideoCaptureSource::supportsCaptureSize):
+        (WebCore::RealtimeVideoCaptureSource::shouldUsePreset):
+        (WebCore::RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate):
+        (WebCore::RealtimeVideoCaptureSource::setSizeAndFrameRate):
+        (WebCore::RealtimeVideoCaptureSource::adaptVideoSample):
+        (WebCore::RealtimeVideoCaptureSource::dispatchMediaSampleToObservers):
+        (WebCore::RealtimeVideoCaptureSource::clientUpdatedSizeAndFrameRate):
+        (WebCore::SizeAndFrameRate::toJSONObject const):
+        (WebCore::SizeAndFrameRate::toJSONString const):
+        * platform/mediastream/RealtimeVideoCaptureSource.h: Added.
+        (WebCore::RealtimeVideoCaptureSource::sampleRotation const):
+        (WebCore::RealtimeVideoCaptureSource::prefersPreset):
+        (WebCore::RealtimeVideoCaptureSource::setFrameRateWithPreset):
+        (WebCore::RealtimeVideoCaptureSource::canResizeVideoFrames const):
+        (WebCore::RealtimeVideoCaptureSource::setDefaultSize):
+        (WebCore::RealtimeVideoCaptureSource::observedFrameRate const):
+        (WTF::LogArgument<WebCore::SizeAndFrameRate>::toString):
+        * platform/mediastream/RealtimeVideoSource.cpp:
+        (WebCore::RealtimeVideoSource::RealtimeVideoSource):
+        (WebCore::m_source):
+        (WebCore::RealtimeVideoSource::~RealtimeVideoSource):
+        (WebCore::RealtimeVideoSource::startProducingData):
+        (WebCore::RealtimeVideoSource::stopProducingData):
+        (WebCore::RealtimeVideoSource::supportsSizeAndFrameRate):
+        (WebCore::RealtimeVideoSource::setSizeAndFrameRate):
+        (WebCore::RealtimeVideoSource::sourceMutedChanged):
+        (WebCore::RealtimeVideoSource::sourceSettingsChanged):
+        (WebCore::RealtimeVideoSource::preventSourceFromStopping):
+        (WebCore::RealtimeVideoSource::sourceStopped):
+        (WebCore::RealtimeVideoSource::videoSampleAvailable):
+        (WebCore::RealtimeVideoSource::clone):
+        * platform/mediastream/RealtimeVideoSource.h:
+        * platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp:
+        (WebCore::GStreamerVideoCaptureSource::GStreamerVideoCaptureSource):
+        * platform/mediastream/gstreamer/GStreamerVideoCaptureSource.h:
+        * platform/mediastream/mac/AVVideoCaptureSource.h:
+        * platform/mediastream/mac/AVVideoCaptureSource.mm:
+        (WebCore::AVVideoCaptureSource::create):
+        (WebCore::AVVideoCaptureSource::AVVideoCaptureSource):
+        * platform/mediastream/mac/MockRealtimeVideoSourceMac.h:
+        * platform/mediastream/mac/MockRealtimeVideoSourceMac.mm:
+        (WebCore::MockRealtimeVideoSource::create):
+        * platform/mock/MockRealtimeVideoSource.cpp:
+        (WebCore::MockRealtimeVideoSource::create):
+        (WebCore::MockRealtimeVideoSource::MockRealtimeVideoSource):
+        (WebCore::MockRealtimeVideoSource::supportsSizeAndFrameRate):
+        (WebCore::MockRealtimeVideoSource::setSizeAndFrameRate):
+        * platform/mock/MockRealtimeVideoSource.h:
+
 2019-06-20  Saam Barati  <sbar...@apple.com>
 
         Unreviewed. More speculative build fixing for watchOS after r246631.

Modified: trunk/Source/WebCore/Headers.cmake (246643 => 246644)


--- trunk/Source/WebCore/Headers.cmake	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/Headers.cmake	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1145,6 +1145,7 @@
     platform/mediastream/RealtimeMediaSourceFactory.h
     platform/mediastream/RealtimeMediaSourceSettings.h
     platform/mediastream/RealtimeMediaSourceSupportedConstraints.h
+    platform/mediastream/RealtimeVideoCaptureSource.h
     platform/mediastream/RealtimeVideoSource.h
     platform/mediastream/VideoPreset.h
     platform/mediastream/WebAudioSourceProvider.h

Modified: trunk/Source/WebCore/Sources.txt (246643 => 246644)


--- trunk/Source/WebCore/Sources.txt	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/Sources.txt	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1872,6 +1872,7 @@
 platform/mediastream/RealtimeMediaSourceSettings.cpp
 platform/mediastream/RealtimeOutgoingAudioSource.cpp
 platform/mediastream/RealtimeOutgoingVideoSource.cpp
+platform/mediastream/RealtimeVideoCaptureSource.cpp
 platform/mediastream/RealtimeVideoSource.cpp
 
 platform/mediastream/libwebrtc/LibWebRTCProvider.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (246643 => 246644)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-06-20 18:55:32 UTC (rev 246644)
@@ -112,7 +112,7 @@
 		07277E4F17D018CC0015534D /* JSMediaStreamAudioDestinationNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4317D018CC0015534D /* JSMediaStreamAudioDestinationNode.h */; };
 		07277E5317D018CC0015534D /* JSMediaStreamTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4717D018CC0015534D /* JSMediaStreamTrack.h */; };
 		07277E5517D018CC0015534D /* JSMediaStreamTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */; };
-		072880D12010F1F60071B255 /* RealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 072880D02010EED70071B255 /* RealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		072880D12010F1F60071B255 /* RealtimeVideoCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 072880D02010EED70071B255 /* RealtimeVideoCaptureSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		072A70401D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */; };
 		072AE1E5183C0741000A5988 /* PluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1DF183C0741000A5988 /* PluginReplacement.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		072AE1E8183C0741000A5988 /* QuickTimePluginReplacement.h in Headers */ = {isa = PBXBuildFile; fileRef = 072AE1E2183C0741000A5988 /* QuickTimePluginReplacement.h */; };
@@ -1117,6 +1117,7 @@
 		41B28B151F8501D300FB52AC /* MediaEndpointConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 41B28B121F8501A300FB52AC /* MediaEndpointConfiguration.h */; };
 		41B28B3D1F860EF300FB52AC /* LibWebRTCProviderCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 41B28B361F860BD000FB52AC /* LibWebRTCProviderCocoa.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41B2A6261EF1BF6D002B9D7A /* WebAudioSourceProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 41B2A6251EF1BF60002B9D7A /* WebAudioSourceProvider.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		41BF204922BA7BE80004F812 /* RealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF204022B947160004F812 /* RealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41C760B10EDE03D300C1655F /* ScriptState.h in Headers */ = {isa = PBXBuildFile; fileRef = 41C760B00EDE03D300C1655F /* ScriptState.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41D015CA0F4B5C71004A662F /* ContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D015C80F4B5C71004A662F /* ContentType.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		41D129CE1F3D0EF600D15E47 /* WorkerGlobalScopeCaches.h in Headers */ = {isa = PBXBuildFile; fileRef = 41FB278D1F34C28200795487 /* WorkerGlobalScopeCaches.h */; };
@@ -5381,8 +5382,8 @@
 		07277E4817D018CC0015534D /* JSMediaStreamTrackEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaStreamTrackEvent.cpp; sourceTree = "<group>"; };
 		07277E4917D018CC0015534D /* JSMediaStreamTrackEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMediaStreamTrackEvent.h; sourceTree = "<group>"; };
 		072847E216EBC5B00043CFA4 /* PlatformTextTrack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformTextTrack.h; sourceTree = "<group>"; };
-		072880CE2010EED60071B255 /* RealtimeVideoSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RealtimeVideoSource.cpp; sourceTree = "<group>"; };
-		072880D02010EED70071B255 /* RealtimeVideoSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeVideoSource.h; sourceTree = "<group>"; };
+		072880CE2010EED60071B255 /* RealtimeVideoCaptureSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RealtimeVideoCaptureSource.cpp; sourceTree = "<group>"; };
+		072880D02010EED70071B255 /* RealtimeVideoCaptureSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeVideoCaptureSource.h; sourceTree = "<group>"; };
 		072A703E1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OverconstrainedErrorEvent.h; sourceTree = "<group>"; };
 		072A703F1D6E8F6200DF0AFC /* OverconstrainedErrorEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OverconstrainedErrorEvent.idl; sourceTree = "<group>"; };
 		072AE1DF183C0741000A5988 /* PluginReplacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginReplacement.h; sourceTree = "<group>"; };
@@ -7388,6 +7389,8 @@
 		41B2A6251EF1BF60002B9D7A /* WebAudioSourceProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAudioSourceProvider.h; sourceTree = "<group>"; };
 		41B459DA1F4CADB90000F6FD /* ReadableStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadableStream.h; sourceTree = "<group>"; };
 		41B459ED1F55EBC70000F6FD /* ReadableStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReadableStream.cpp; sourceTree = "<group>"; };
+		41BF204022B947160004F812 /* RealtimeVideoSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RealtimeVideoSource.h; sourceTree = "<group>"; };
+		41BF204222B947170004F812 /* RealtimeVideoSource.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RealtimeVideoSource.cpp; sourceTree = "<group>"; };
 		41C760B00EDE03D300C1655F /* ScriptState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptState.h; sourceTree = "<group>"; };
 		41C7E1051E6A54360027B4DE /* CanvasCaptureMediaStreamTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasCaptureMediaStreamTrack.cpp; sourceTree = "<group>"; };
 		41C7E1061E6A54360027B4DE /* CanvasCaptureMediaStreamTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasCaptureMediaStreamTrack.h; sourceTree = "<group>"; };
@@ -15849,8 +15852,10 @@
 				41103AA81E39790A00769F03 /* RealtimeOutgoingAudioSource.h */,
 				5CDD833B1E4324BB00621E92 /* RealtimeOutgoingVideoSource.cpp */,
 				5CDD833C1E4324BB00621E92 /* RealtimeOutgoingVideoSource.h */,
-				072880CE2010EED60071B255 /* RealtimeVideoSource.cpp */,
-				072880D02010EED70071B255 /* RealtimeVideoSource.h */,
+				072880CE2010EED60071B255 /* RealtimeVideoCaptureSource.cpp */,
+				072880D02010EED70071B255 /* RealtimeVideoCaptureSource.h */,
+				41BF204222B947170004F812 /* RealtimeVideoSource.cpp */,
+				41BF204022B947160004F812 /* RealtimeVideoSource.h */,
 				3135910C1E7DDCB600F30630 /* RTCBundlePolicy.h */,
 				07221BA217CF0AD400848E51 /* RTCDataChannelHandler.h */,
 				07221BA317CF0AD400848E51 /* RTCDataChannelHandlerClient.h */,
@@ -31071,7 +31076,8 @@
 				07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */,
 				41103AAC1E39791000769F03 /* RealtimeOutgoingAudioSource.h in Headers */,
 				41103AAC1E39791000769F14 /* RealtimeOutgoingAudioSourceCocoa.h in Headers */,
-				072880D12010F1F60071B255 /* RealtimeVideoSource.h in Headers */,
+				072880D12010F1F60071B255 /* RealtimeVideoCaptureSource.h in Headers */,
+				41BF204922BA7BE80004F812 /* RealtimeVideoSource.h in Headers */,
 				91B952241F58A58F00931DC2 /* RecordingSwizzleTypes.h in Headers */,
 				BC4368E80C226E32005EFB5F /* Rect.h in Headers */,
 				FD45A958175D414C00C21EC8 /* RectangleShape.h in Headers */,

Modified: trunk/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp	2019-06-20 18:55:32 UTC (rev 246644)
@@ -155,7 +155,7 @@
 
 Ref<MediaStreamTrackPrivate> MediaStreamTrackPrivate::clone()
 {
-    auto clonedMediaStreamTrackPrivate = create(m_logger.copyRef(), m_source.copyRef());
+    auto clonedMediaStreamTrackPrivate = create(m_logger.copyRef(), m_source->clone());
 
     clonedMediaStreamTrackPrivate->m_isEnabled = this->m_isEnabled;
     clonedMediaStreamTrackPrivate->m_isEnded = this->m_isEnded;
@@ -162,6 +162,9 @@
     clonedMediaStreamTrackPrivate->m_contentHint = this->m_contentHint;
     clonedMediaStreamTrackPrivate->updateReadyState();
 
+    if (isProducingData())
+        clonedMediaStreamTrackPrivate->startProducingData();
+
     return clonedMediaStreamTrackPrivate;
 }
 

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -96,6 +96,8 @@
 
     virtual ~RealtimeMediaSource() = default;
 
+    virtual Ref<RealtimeMediaSource> clone() { return *this; }
+
     const String& hashedId() const;
     String deviceIDHashSalt() const;
 
@@ -224,6 +226,8 @@
     void videoSampleAvailable(MediaSample&);
     void audioSamplesAvailable(const MediaTime&, const PlatformAudioData&, const AudioStreamDescription&, size_t);
 
+    void forEachObserver(const WTF::Function<void(Observer&)>&) const;
+
 private:
     virtual void startProducingData() { }
     virtual void stopProducingData() { }
@@ -231,8 +235,6 @@
 
     virtual void hasEnded() { }
 
-    void forEachObserver(const WTF::Function<void(Observer&)>&) const;
-
 #if !RELEASE_LOG_DISABLED
     RefPtr<const Logger> m_logger;
     const void* m_logIdentifier;

Copied: trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp (from rev 246643, trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp) (0 => 246644)


--- trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.cpp	2019-06-20 18:55:32 UTC (rev 246644)
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. ``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 APPLE INC. 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 "config.h"
+#include "RealtimeVideoCaptureSource.h"
+
+#if ENABLE(MEDIA_STREAM)
+#include "CaptureDevice.h"
+#include "Logging.h"
+#include "RealtimeMediaSourceCenter.h"
+#include "RealtimeMediaSourceSettings.h"
+#include "RemoteVideoSample.h"
+#include <wtf/JSONValues.h>
+
+#if PLATFORM(COCOA)
+#include "ImageTransferSessionVT.h"
+#endif
+
+namespace WebCore {
+
+RealtimeVideoCaptureSource::RealtimeVideoCaptureSource(String&& name, String&& id, String&& hashSalt)
+    : RealtimeMediaSource(Type::Video, WTFMove(name), WTFMove(id), WTFMove(hashSalt))
+{
+}
+
+RealtimeVideoCaptureSource::~RealtimeVideoCaptureSource()
+{
+#if PLATFORM(IOS_FAMILY)
+    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().unsetActiveSource(*this);
+#endif
+}
+
+void RealtimeVideoCaptureSource::prepareToProduceData()
+{
+    ASSERT(frameRate());
+
+#if PLATFORM(IOS_FAMILY)
+    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().setActiveSource(*this);
+#endif
+
+    if (size().isEmpty() && !m_defaultSize.isEmpty())
+        setSize(m_defaultSize);
+}
+
+const Vector<Ref<VideoPreset>>& RealtimeVideoCaptureSource::presets()
+{
+    if (m_presets.isEmpty())
+        generatePresets();
+
+    ASSERT(!m_presets.isEmpty());
+    return m_presets;
+}
+
+void RealtimeVideoCaptureSource::setSupportedPresets(Vector<VideoPresetData>&& presetData)
+{
+    Vector<Ref<VideoPreset>> presets;
+
+    for (auto& data : presetData)
+        presets.append(VideoPreset::create(WTFMove(data)));
+
+    setSupportedPresets(WTFMove(presets));
+}
+
+void RealtimeVideoCaptureSource::setSupportedPresets(const Vector<Ref<VideoPreset>>& presets)
+{
+    m_presets = WTF::map(presets, [](auto& preset) {
+        return preset.copyRef();
+    });
+
+    for (auto& preset : m_presets) {
+        std::sort(preset->frameRateRanges.begin(), preset->frameRateRanges.end(),
+            [&] (const auto& a, const auto& b) -> bool {
+                return a.minimum < b.minimum;
+        });
+    }
+}
+
+const Vector<IntSize>& RealtimeVideoCaptureSource::standardVideoSizes()
+{
+    static const auto sizes = makeNeverDestroyed([] {
+        static IntSize videoSizes[] = {
+            { 112, 112 },
+            { 160, 160 },
+            { 160, 120 }, // 4:3, QQVGA
+            { 176, 144 }, // 4:3, QCIF
+            { 192, 192 },
+            { 192, 112 }, // 16:9
+            { 192, 144 }, // 3:4
+            { 240, 240 },
+            { 240, 160 }, // 3:2, HQVGA
+            { 320, 320 },
+            { 320, 180 }, // 16:9
+            { 320, 240 }, // 4:3, QVGA
+            { 352, 288 }, // CIF
+            { 480, 272 }, // 16:9
+            { 480, 360 }, // 4:3
+            { 480, 480 },
+            { 640, 640 },
+            { 640, 360 }, // 16:9, 360p nHD
+            { 640, 480 }, // 4:3
+            { 720, 720 },
+            { 800, 600 }, // 4:3, SVGA
+            { 960, 540 }, // 16:9, qHD
+            { 1024, 600 }, // 16:9, WSVGA
+            { 1024, 768 }, // 4:3, XGA
+            { 1280, 960 }, // 4:3
+            { 1280, 1024 }, // 5:4, SXGA
+            { 1280, 720 }, // 16:9, WXGA
+            { 1366, 768 }, // 16:9, HD
+            { 1600, 1200}, // 4:3, UXGA
+            { 1920, 1080 }, // 16:9, 1080p FHD
+            { 2560, 1440 }, // 16:9, QHD
+            { 2592, 1936 },
+            { 3264, 2448 }, // 3:4
+            { 3840, 2160 }, // 16:9, 4K UHD
+        };
+        Vector<IntSize> sizes;
+        for (auto& size : videoSizes)
+            sizes.append(size);
+
+        return sizes;
+    }());
+
+    return sizes.get();
+}
+template <typename ValueType>
+static void updateMinMax(ValueType& min, ValueType& max, ValueType value)
+{
+    min = std::min<ValueType>(min, value);
+    max = std::max<ValueType>(max, value);
+}
+
+void RealtimeVideoCaptureSource::updateCapabilities(RealtimeMediaSourceCapabilities& capabilities)
+{
+    ASSERT(!presets().isEmpty());
+
+    int minimumWidth = std::numeric_limits<int>::max();
+    int maximumWidth = 0;
+    int minimumHeight = std::numeric_limits<int>::max();
+    int maximumHeight = 0;
+    double minimumAspectRatio = std::numeric_limits<double>::max();
+    double maximumAspectRatio = 0;
+    double minimumFrameRate = std::numeric_limits<double>::max();
+    double maximumFrameRate = 0;
+    for (const auto& preset : presets()) {
+        const auto& size = preset->size;
+        updateMinMax(minimumWidth, maximumWidth, size.width());
+        updateMinMax(minimumHeight, maximumHeight, size.height());
+        updateMinMax(minimumAspectRatio, maximumAspectRatio, static_cast<double>(size.width()) / size.height());
+
+        for (const auto& rate : preset->frameRateRanges) {
+            updateMinMax(minimumFrameRate, maximumFrameRate, rate.minimum);
+            updateMinMax(minimumFrameRate, maximumFrameRate, rate.maximum);
+        }
+    }
+
+    if (canResizeVideoFrames()) {
+        minimumWidth = 1;
+        minimumHeight = 1;
+    }
+
+    capabilities.setWidth({ minimumWidth, maximumWidth });
+    capabilities.setHeight({ minimumHeight, maximumHeight });
+    capabilities.setAspectRatio({ minimumAspectRatio, maximumAspectRatio });
+    capabilities.setFrameRate({ minimumFrameRate, maximumFrameRate });
+}
+
+bool RealtimeVideoCaptureSource::supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
+{
+    if (!width && !height && !frameRate)
+        return true;
+
+    return !!bestSupportedSizeAndFrameRate(width, height, frameRate);
+}
+
+bool RealtimeVideoCaptureSource::frameRateRangeIncludesRate(const FrameRateRange& range, double frameRate)
+{
+    const double epsilon = 0.001;
+    return frameRate + epsilon >= range.minimum && frameRate - epsilon <= range.maximum;
+}
+
+bool RealtimeVideoCaptureSource::presetSupportsFrameRate(RefPtr<VideoPreset> preset, double frameRate)
+{
+    for (const auto& range : preset->frameRateRanges) {
+        if (frameRateRangeIncludesRate(range, frameRate))
+            return true;
+    }
+
+    return false;
+}
+
+bool RealtimeVideoCaptureSource::supportsCaptureSize(Optional<int> width, Optional<int> height, const Function<bool(const IntSize&)>&& function)
+{
+    if (width && height)
+        return function({ width.value(), height.value() });
+
+    if (width) {
+        for (auto& size : standardVideoSizes()) {
+            if (width.value() == size.width() && function({ size.width(), size.height() }))
+                return true;
+        }
+
+        return false;
+    }
+
+    for (auto& size : standardVideoSizes()) {
+        if (height.value() == size.height() && function({ size.width(), size.height() }))
+            return true;
+    }
+
+    return false;
+}
+
+bool RealtimeVideoCaptureSource::shouldUsePreset(VideoPreset& current, VideoPreset& candidate)
+{
+    return candidate.size.width() <= current.size.width() && candidate.size.height() <= current.size.height() && prefersPreset(candidate);
+}
+
+Optional<RealtimeVideoCaptureSource::CaptureSizeAndFrameRate> RealtimeVideoCaptureSource::bestSupportedSizeAndFrameRate(Optional<int> requestedWidth, Optional<int> requestedHeight, Optional<double> requestedFrameRate)
+{
+    if (!requestedWidth && !requestedHeight && !requestedFrameRate)
+        return { };
+
+    if (!requestedWidth && !requestedHeight && !size().isEmpty()) {
+        requestedWidth = size().width();
+        requestedHeight = size().height();
+    }
+    if (!requestedFrameRate)
+        requestedFrameRate = frameRate();
+
+    CaptureSizeAndFrameRate result;
+    RefPtr<VideoPreset> exactSizePreset;
+    RefPtr<VideoPreset> aspectRatioPreset;
+    IntSize aspectRatioMatchSize;
+    RefPtr<VideoPreset> resizePreset;
+    IntSize resizeSize;
+
+    for (const auto& preset : presets()) {
+        const auto& presetSize = preset->size;
+
+        if (!presetSupportsFrameRate(&preset.get(), requestedFrameRate.value()))
+            continue;
+
+        if (!requestedWidth && !requestedHeight) {
+            result.requestedFrameRate = requestedFrameRate.value();
+            return result;
+        }
+
+        // Don't look at presets smaller than the requested resolution because we never want to resize larger.
+        if ((requestedWidth && presetSize.width() < requestedWidth.value()) || (requestedHeight && presetSize.height() < requestedHeight.value()))
+            continue;
+
+        auto lookForExactSizeMatch = [&] (const IntSize& size) -> bool {
+            return preset->size == size;
+        };
+        if (supportsCaptureSize(requestedWidth, requestedHeight, WTFMove(lookForExactSizeMatch))) {
+            if (!exactSizePreset || prefersPreset(preset))
+                exactSizePreset = &preset.get();
+            continue;
+        }
+
+        IntSize encodingSize;
+        auto lookForAspectRatioMatch = [this, &preset, &encodingSize] (const IntSize& size) -> bool {
+            auto aspectRatio = [] (const IntSize size) -> double {
+                return size.width() / static_cast<double>(size.height());
+            };
+            if (std::abs(aspectRatio(preset->size) - aspectRatio(size)) > 10e-7 || !canResizeVideoFrames())
+                return false;
+
+            encodingSize = size;
+            return true;
+        };
+        if (supportsCaptureSize(requestedWidth, requestedHeight, WTFMove(lookForAspectRatioMatch))) {
+            if (!aspectRatioPreset || shouldUsePreset(*aspectRatioPreset, preset)) {
+                aspectRatioPreset = &preset.get();
+                aspectRatioMatchSize = encodingSize;
+            }
+        }
+
+        if (exactSizePreset || aspectRatioPreset)
+            continue;
+
+        if ((requestedWidth && requestedWidth.value() > preset->size.width()) || (requestedHeight && requestedHeight.value() > preset->size.height()))
+            continue;
+
+        if (requestedWidth && requestedHeight) {
+            if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
+                resizePreset = &preset.get();
+                resizeSize = { requestedWidth.value(), requestedHeight.value() };
+            }
+        } else {
+            for (auto& standardSize : standardVideoSizes()) {
+                if (standardSize.width() > preset->size.width() || standardSize.height() > preset->size.height())
+                    break;
+                if ((requestedWidth && requestedWidth.value() != standardSize.width()) || (requestedHeight && requestedHeight.value() != standardSize.height()))
+                    continue;
+
+                if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
+                    resizePreset = &preset.get();
+                    resizeSize = standardSize;
+                }
+            }
+
+            if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
+                resizePreset = &preset.get();
+                if (requestedWidth)
+                    resizeSize = { requestedWidth.value(), requestedWidth.value() * preset->size.height() / preset->size.width()};
+                else
+                    resizeSize = { requestedHeight.value() * preset->size.width() / preset->size.height(), requestedHeight.value() };
+            }
+        }
+    }
+
+    if (!exactSizePreset && !aspectRatioPreset && !resizePreset)
+        return { };
+
+    result.requestedFrameRate = requestedFrameRate.value();
+    if (exactSizePreset) {
+        result.encodingPreset = exactSizePreset;
+        result.requestedSize = exactSizePreset->size;
+        return result;
+    }
+
+    if (aspectRatioPreset) {
+        result.encodingPreset = aspectRatioPreset;
+        result.requestedSize = aspectRatioMatchSize;
+        return result;
+    }
+
+    result.encodingPreset = resizePreset;
+    result.requestedSize = resizeSize;
+    return result;
+}
+
+void RealtimeVideoCaptureSource::setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
+{
+    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, SizeAndFrameRate { width, height, frameRate });
+
+    auto size = this->size();
+    if (!width && !height && !size.isEmpty()) {
+        width = size.width();
+        height = size.height();
+    }
+
+    Optional<RealtimeVideoCaptureSource::CaptureSizeAndFrameRate> match = bestSupportedSizeAndFrameRate(width, height, frameRate);
+    ASSERT(match);
+    if (!match)
+        return;
+
+    setFrameRateWithPreset(match->requestedFrameRate, match->encodingPreset);
+
+    if (!match->requestedSize.isEmpty())
+        setSize(match->requestedSize);
+    setFrameRate(match->requestedFrameRate);
+}
+
+RefPtr<MediaSample> RealtimeVideoCaptureSource::adaptVideoSample(MediaSample& sample)
+{
+    MediaTime sampleTime = sample.outputPresentationTime();
+    if (!sampleTime || !sampleTime.isValid())
+        sampleTime = sample.presentationTime();
+
+    auto frameTime = sampleTime.toDouble();
+    m_observedFrameTimeStamps.append(frameTime);
+    m_observedFrameTimeStamps.removeAllMatching([&](auto time) {
+        return time <= frameTime - 2;
+    });
+
+    auto interval = m_observedFrameTimeStamps.last() - m_observedFrameTimeStamps.first();
+    if (interval > 1)
+        m_observedFrameRate = (m_observedFrameTimeStamps.size() / interval);
+
+    auto mediaSample = makeRefPtr(&sample);
+
+#if PLATFORM(COCOA)
+    if (!isRemote()) {
+        auto size = this->size();
+        if (!size.isEmpty() && size != expandedIntSize(sample.presentationSize())) {
+
+            if (!m_imageTransferSession || m_imageTransferSession->pixelFormat() != sample.videoPixelFormat())
+                m_imageTransferSession = ImageTransferSessionVT::create(sample.videoPixelFormat());
+
+            if (m_imageTransferSession) {
+                mediaSample = m_imageTransferSession->convertMediaSample(sample, size);
+                if (!mediaSample) {
+                    ASSERT_NOT_REACHED();
+                    return nullptr;
+                }
+            }
+        }
+    }
+#endif
+
+    return mediaSample.releaseNonNull();
+}
+
+void RealtimeVideoCaptureSource::dispatchMediaSampleToObservers(MediaSample& sample)
+{
+    if (auto mediaSample = adaptVideoSample(sample))
+        videoSampleAvailable(*mediaSample);
+}
+
+void RealtimeVideoCaptureSource::clientUpdatedSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
+{
+    // FIXME: We only change settings if capture resolution is below requested one. We should get the best preset for all clients.
+    auto& settings = this->settings();
+    if (width && *width < static_cast<int>(settings.width()))
+        width = { };
+    if (height && *height < static_cast<int>(settings.height()))
+        height = { };
+
+    // FIXME: handle frameRate potential increase.
+    if (!width && !height)
+        return;
+
+    auto match = bestSupportedSizeAndFrameRate(width, height, frameRate);
+    ERROR_LOG_IF(loggerPtr() && !match, LOGIDENTIFIER, "unable to find a preset that would match the size and frame rate");
+    if (!match)
+        return;
+
+    setFrameRateWithPreset(match->requestedFrameRate, match->encodingPreset);
+    setSize(match->encodingPreset->size);
+    setFrameRate(match->requestedFrameRate);
+}
+
+#if !RELEASE_LOG_DISABLED
+Ref<JSON::Object> SizeAndFrameRate::toJSONObject() const
+{
+    auto object = JSON::Object::create();
+
+    object->setDouble("width"_s, width ? width.value() : 0);
+    object->setDouble("height"_s, height ? height.value() : 0);
+    object->setDouble("frameRate"_s, frameRate ? frameRate.value() : 0);
+
+    return object;
+}
+
+String SizeAndFrameRate::toJSONString() const
+{
+    return toJSONObject()->toJSONString();
+}
+#endif
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Copied: trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.h (from rev 246643, trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.h) (0 => 246644)


--- trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeVideoCaptureSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. ``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 APPLE INC. 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.
+ */
+
+#pragma once
+
+#if ENABLE(MEDIA_STREAM)
+
+#include "ImageBuffer.h"
+#include "MediaSample.h"
+#include "RealtimeMediaSource.h"
+#include "VideoPreset.h"
+#include <wtf/Lock.h>
+#include <wtf/RunLoop.h>
+
+namespace WebCore {
+
+class ImageTransferSessionVT;
+
+class RealtimeVideoCaptureSource : public RealtimeMediaSource {
+public:
+    virtual ~RealtimeVideoCaptureSource();
+
+    void clientUpdatedSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate);
+
+    bool supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>) override;
+    virtual void generatePresets() = 0;
+    virtual MediaSample::VideoRotation sampleRotation() const { return MediaSample::VideoRotation::None; }
+
+protected:
+    RealtimeVideoCaptureSource(String&& name, String&& id, String&& hashSalt);
+
+    void prepareToProduceData();
+    void setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>) override;
+
+    virtual bool prefersPreset(VideoPreset&) { return true; }
+    virtual void setFrameRateWithPreset(double, RefPtr<VideoPreset>) { };
+    virtual bool canResizeVideoFrames() const { return false; }
+    bool shouldUsePreset(VideoPreset& current, VideoPreset& candidate);
+
+    void setSupportedPresets(const Vector<Ref<VideoPreset>>&);
+    void setSupportedPresets(Vector<VideoPresetData>&&);
+    const Vector<Ref<VideoPreset>>& presets();
+
+    bool frameRateRangeIncludesRate(const FrameRateRange&, double);
+
+    void updateCapabilities(RealtimeMediaSourceCapabilities&);
+
+    void setDefaultSize(const IntSize& size) { m_defaultSize = size; }
+
+    double observedFrameRate() const { return m_observedFrameRate; }
+
+    void dispatchMediaSampleToObservers(MediaSample&);
+    const Vector<IntSize>& standardVideoSizes();
+    RefPtr<MediaSample> adaptVideoSample(MediaSample&);
+
+private:
+    struct CaptureSizeAndFrameRate {
+        RefPtr<VideoPreset> encodingPreset;
+        IntSize requestedSize;
+        double requestedFrameRate { 0 };
+    };
+    bool supportsCaptureSize(Optional<int>, Optional<int>, const Function<bool(const IntSize&)>&&);
+    Optional<CaptureSizeAndFrameRate> bestSupportedSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>);
+    bool presetSupportsFrameRate(RefPtr<VideoPreset>, double);
+
+#if !RELEASE_LOG_DISABLED
+    const char* logClassName() const override { return "RealtimeVideoCaptureSource"; }
+#endif
+
+    Vector<Ref<VideoPreset>> m_presets;
+    Deque<double> m_observedFrameTimeStamps;
+    double m_observedFrameRate { 0 };
+    IntSize m_defaultSize;
+#if PLATFORM(COCOA)
+    std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;
+#endif
+};
+
+struct SizeAndFrameRate {
+    Optional<int> width;
+    Optional<int> height;
+    Optional<double> frameRate;
+
+    String toJSONString() const;
+    Ref<JSON::Object> toJSONObject() const;
+};
+
+} // namespace WebCore
+
+namespace WTF {
+template<typename Type> struct LogArgument;
+template <>
+struct LogArgument<WebCore::SizeAndFrameRate> {
+    static String toString(const WebCore::SizeAndFrameRate& size)
+    {
+        return size.toJSONString();
+    }
+};
+}; // namespace WTF
+
+#endif // ENABLE(MEDIA_STREAM)
+

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.cpp	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,416 +27,125 @@
 #include "RealtimeVideoSource.h"
 
 #if ENABLE(MEDIA_STREAM)
-#include "CaptureDevice.h"
-#include "Logging.h"
-#include "RealtimeMediaSourceCenter.h"
-#include "RealtimeMediaSourceSettings.h"
-#include "RemoteVideoSample.h"
-#include <wtf/JSONValues.h>
 
-#if PLATFORM(COCOA)
-#include "ImageTransferSessionVT.h"
-#endif
-
 namespace WebCore {
 
-RealtimeVideoSource::RealtimeVideoSource(String&& name, String&& id, String&& hashSalt)
-    : RealtimeMediaSource(Type::Video, WTFMove(name), WTFMove(id), WTFMove(hashSalt))
+RealtimeVideoSource::RealtimeVideoSource(Ref<RealtimeVideoCaptureSource>&& source)
+    : RealtimeVideoCaptureSource(String { source->name() }, String { source->persistentID() }, String { source->deviceIDHashSalt() })
+    , m_source(WTFMove(source))
 {
+    m_source->addObserver(*this);
+    m_currentSettings = m_source->settings();
 }
 
 RealtimeVideoSource::~RealtimeVideoSource()
 {
-#if PLATFORM(IOS_FAMILY)
-    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().unsetActiveSource(*this);
-#endif
+    m_source->removeObserver(*this);
 }
 
-void RealtimeVideoSource::prepareToProduceData()
+void RealtimeVideoSource::startProducingData()
 {
-    ASSERT(frameRate());
-
-#if PLATFORM(IOS_FAMILY)
-    RealtimeMediaSourceCenter::singleton().videoCaptureFactory().setActiveSource(*this);
-#endif
-
-    if (size().isEmpty() && !m_defaultSize.isEmpty())
-        setSize(m_defaultSize);
+    m_source->start();
 }
 
-const Vector<Ref<VideoPreset>>& RealtimeVideoSource::presets()
+void RealtimeVideoSource::stopProducingData()
 {
-    if (m_presets.isEmpty())
-        generatePresets();
-
-    ASSERT(!m_presets.isEmpty());
-    return m_presets;
+    m_source->stop();
 }
 
-void RealtimeVideoSource::setSupportedPresets(Vector<VideoPresetData>&& presetData)
+bool RealtimeVideoSource::supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
 {
-    Vector<Ref<VideoPreset>> presets;
-
-    for (auto& data : presetData)
-        presets.append(VideoPreset::create(WTFMove(data)));
-
-    setSupportedPresets(WTFMove(presets));
+    return m_source->supportsSizeAndFrameRate(width, height, frameRate);
 }
 
-void RealtimeVideoSource::setSupportedPresets(const Vector<Ref<VideoPreset>>& presets)
+void RealtimeVideoSource::setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
 {
-    m_presets = WTF::map(presets, [](auto& preset) {
-        return preset.copyRef();
-    });
-
-    for (auto& preset : m_presets) {
-        std::sort(preset->frameRateRanges.begin(), preset->frameRateRanges.end(),
-            [&] (const auto& a, const auto& b) -> bool {
-                return a.minimum < b.minimum;
-        });
+    if (!width && !height) {
+        width = size().width();
+        height = size().height();
     }
-}
 
-const Vector<IntSize>& RealtimeVideoSource::standardVideoSizes()
-{
-    static const auto sizes = makeNeverDestroyed([] {
-        static IntSize videoSizes[] = {
-            { 112, 112 },
-            { 160, 160 },
-            { 160, 120 }, // 4:3, QQVGA
-            { 176, 144 }, // 4:3, QCIF
-            { 192, 192 },
-            { 192, 112 }, // 16:9
-            { 192, 144 }, // 3:4
-            { 240, 240 },
-            { 240, 160 }, // 3:2, HQVGA
-            { 320, 320 },
-            { 320, 180 }, // 16:9
-            { 320, 240 }, // 4:3, QVGA
-            { 352, 288 }, // CIF
-            { 480, 272 }, // 16:9
-            { 480, 360 }, // 4:3
-            { 480, 480 },
-            { 640, 640 },
-            { 640, 360 }, // 16:9, 360p nHD
-            { 640, 480 }, // 4:3
-            { 720, 720 },
-            { 800, 600 }, // 4:3, SVGA
-            { 960, 540 }, // 16:9, qHD
-            { 1024, 600 }, // 16:9, WSVGA
-            { 1024, 768 }, // 4:3, XGA
-            { 1280, 960 }, // 4:3
-            { 1280, 1024 }, // 5:4, SXGA
-            { 1280, 720 }, // 16:9, WXGA
-            { 1366, 768 }, // 16:9, HD
-            { 1600, 1200}, // 4:3, UXGA
-            { 1920, 1080 }, // 16:9, 1080p FHD
-            { 2560, 1440 }, // 16:9, QHD
-            { 2592, 1936 },
-            { 3264, 2448 }, // 3:4
-            { 3840, 2160 }, // 16:9, 4K UHD
-        };
-        Vector<IntSize> sizes;
-        for (auto& size : videoSizes)
-            sizes.append(size);
+    m_source->clientUpdatedSizeAndFrameRate(width, height, frameRate);
+    auto sourceSize = m_source->size();
+    ASSERT(sourceSize.height());
+    ASSERT(sourceSize.width());
 
-        return sizes;
-    }());
+    if (!width)
+        width = sourceSize.width() * height.value() / sourceSize.height();
+    m_currentSettings.setWidth(*width);
 
-    return sizes.get();
-}
-template <typename ValueType>
-static void updateMinMax(ValueType& min, ValueType& max, ValueType value)
-{
-    min = std::min<ValueType>(min, value);
-    max = std::max<ValueType>(max, value);
-}
+    if (!height)
+        height = sourceSize.height() * width.value() / sourceSize.width();
+    m_currentSettings.setHeight(*height);
 
-void RealtimeVideoSource::updateCapabilities(RealtimeMediaSourceCapabilities& capabilities)
-{
-    ASSERT(!presets().isEmpty());
+    if (frameRate)
+        m_currentSettings.setFrameRate(static_cast<float>(*frameRate));
 
-    int minimumWidth = std::numeric_limits<int>::max();
-    int maximumWidth = 0;
-    int minimumHeight = std::numeric_limits<int>::max();
-    int maximumHeight = 0;
-    double minimumAspectRatio = std::numeric_limits<double>::max();
-    double maximumAspectRatio = 0;
-    double minimumFrameRate = std::numeric_limits<double>::max();
-    double maximumFrameRate = 0;
-    for (const auto& preset : presets()) {
-        const auto& size = preset->size;
-        updateMinMax(minimumWidth, maximumWidth, size.width());
-        updateMinMax(minimumHeight, maximumHeight, size.height());
-        updateMinMax(minimumAspectRatio, maximumAspectRatio, static_cast<double>(size.width()) / size.height());
-
-        for (const auto& rate : preset->frameRateRanges) {
-            updateMinMax(minimumFrameRate, maximumFrameRate, rate.minimum);
-            updateMinMax(minimumFrameRate, maximumFrameRate, rate.maximum);
-        }
-    }
-
-    if (canResizeVideoFrames()) {
-        minimumWidth = 1;
-        minimumHeight = 1;
-        for (auto& size : standardVideoSizes()) {
-            if (size.width() < minimumWidth || size.height() < minimumHeight)
-                minimumAspectRatio = std::min(minimumAspectRatio, static_cast<double>(size.width()) / size.height());
-        }
-    }
-
-    capabilities.setWidth({ minimumWidth, maximumWidth });
-    capabilities.setHeight({ minimumHeight, maximumHeight });
-    capabilities.setAspectRatio({ minimumAspectRatio, maximumAspectRatio });
-    capabilities.setFrameRate({ minimumFrameRate, maximumFrameRate });
+    RealtimeMediaSource::setSizeAndFrameRate(width, height, frameRate);
 }
 
-bool RealtimeVideoSource::supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
+void RealtimeVideoSource::sourceMutedChanged()
 {
-    if (!width && !height && !frameRate)
-        return true;
-
-    return !!bestSupportedSizeAndFrameRate(width, height, frameRate);
+    notifyMutedChange(m_source->muted());
 }
 
-bool RealtimeVideoSource::frameRateRangeIncludesRate(const FrameRateRange& range, double frameRate)
+void RealtimeVideoSource::sourceSettingsChanged()
 {
-    const double epsilon = 0.001;
-    return frameRate + epsilon >= range.minimum && frameRate - epsilon <= range.maximum;
-}
-
-bool RealtimeVideoSource::presetSupportsFrameRate(RefPtr<VideoPreset> preset, double frameRate)
-{
-    for (const auto& range : preset->frameRateRanges) {
-        if (frameRateRangeIncludesRate(range, frameRate))
-            return true;
+    auto rotation = m_source->sampleRotation();
+    if (rotation == MediaSample::VideoRotation::Left || rotation == MediaSample::VideoRotation::Right) {
+        auto size = this->size();
+        size = size.transposedSize();
+        m_currentSettings.setWidth(size.width());
+        m_currentSettings.setHeight(size.height());
     }
 
-    return false;
+    forEachObserver([&](auto& observer) {
+        observer.sourceSettingsChanged();
+    });
 }
 
-bool RealtimeVideoSource::supportsCaptureSize(Optional<int> width, Optional<int> height, const Function<bool(const IntSize&)>&& function)
+bool RealtimeVideoSource::preventSourceFromStopping()
 {
-    if (width && height)
-        return function({ width.value(), height.value() });
-
-    if (width) {
-        for (auto& size : standardVideoSizes()) {
-            if (width.value() == size.width() && function({ size.width(), size.height() }))
-                return true;
-        }
-
+    if (!isProducingData())
         return false;
-    }
 
-    for (auto& size : standardVideoSizes()) {
-        if (height.value() == size.height() && function({ size.width(), size.height() }))
-            return true;
-    }
-
-    return false;
+    bool hasObserverPreventingStopping = false;
+    forEachObserver([&](auto& observer) {
+        if (observer.preventSourceFromStopping())
+            hasObserverPreventingStopping = true;
+    });
+    return hasObserverPreventingStopping;
 }
 
-bool RealtimeVideoSource::shouldUsePreset(VideoPreset& current, VideoPreset& candidate)
+void RealtimeVideoSource::sourceStopped()
 {
-    return candidate.size.width() <= current.size.width() && candidate.size.height() <= current.size.height() && prefersPreset(candidate);
-}
-
-Optional<RealtimeVideoSource::CaptureSizeAndFrameRate> RealtimeVideoSource::bestSupportedSizeAndFrameRate(Optional<int> requestedWidth, Optional<int> requestedHeight, Optional<double> requestedFrameRate)
-{
-    if (!requestedWidth && !requestedHeight && !requestedFrameRate)
-        return { };
-
-    if (!requestedWidth && !requestedHeight && !size().isEmpty()) {
-        requestedWidth = size().width();
-        requestedHeight = size().height();
+    if (m_source->captureDidFail()) {
+        captureFailed();
+        return;
     }
-    if (!requestedFrameRate)
-        requestedFrameRate = frameRate();
-
-    CaptureSizeAndFrameRate result;
-    RefPtr<VideoPreset> exactSizePreset;
-    RefPtr<VideoPreset> aspectRatioPreset;
-    IntSize aspectRatioMatchSize;
-    RefPtr<VideoPreset> resizePreset;
-    IntSize resizeSize;
-
-    for (const auto& preset : presets()) {
-        const auto& presetSize = preset->size;
-
-        if (!presetSupportsFrameRate(&preset.get(), requestedFrameRate.value()))
-            continue;
-
-        if (!requestedWidth && !requestedHeight) {
-            result.requestedFrameRate = requestedFrameRate.value();
-            return result;
-        }
-
-        // Don't look at presets smaller than the requested resolution because we never want to resize larger.
-        if ((requestedWidth && presetSize.width() < requestedWidth.value()) || (requestedHeight && presetSize.height() < requestedHeight.value()))
-            continue;
-
-        auto lookForExactSizeMatch = [&] (const IntSize& size) -> bool {
-            return preset->size == size;
-        };
-        if (supportsCaptureSize(requestedWidth, requestedHeight, WTFMove(lookForExactSizeMatch))) {
-            if (!exactSizePreset || prefersPreset(preset))
-                exactSizePreset = &preset.get();
-            continue;
-        }
-
-        IntSize encodingSize;
-        auto lookForAspectRatioMatch = [this, &preset, &encodingSize] (const IntSize& size) -> bool {
-            auto aspectRatio = [] (const IntSize size) -> double {
-                return size.width() / static_cast<double>(size.height());
-            };
-            if (std::abs(aspectRatio(preset->size) - aspectRatio(size)) > 10e-7 || !canResizeVideoFrames())
-                return false;
-
-            encodingSize = size;
-            return true;
-        };
-        if (supportsCaptureSize(requestedWidth, requestedHeight, WTFMove(lookForAspectRatioMatch))) {
-            if (!aspectRatioPreset || shouldUsePreset(*aspectRatioPreset, preset)) {
-                aspectRatioPreset = &preset.get();
-                aspectRatioMatchSize = encodingSize;
-            }
-        }
-
-        if (exactSizePreset || aspectRatioPreset)
-            continue;
-
-        if ((requestedWidth && requestedWidth.value() > preset->size.width()) || (requestedHeight && requestedHeight.value() > preset->size.height()))
-            continue;
-
-        if (requestedWidth && requestedHeight) {
-            if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
-                resizePreset = &preset.get();
-                resizeSize = { requestedWidth.value(), requestedHeight.value() };
-            }
-        } else {
-            for (auto& standardSize : standardVideoSizes()) {
-                if (standardSize.width() > preset->size.width() || standardSize.height() > preset->size.height())
-                    break;
-                if ((requestedWidth && requestedWidth.value() != standardSize.width()) || (requestedHeight && requestedHeight.value() != standardSize.height()))
-                    continue;
-
-                if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
-                    resizePreset = &preset.get();
-                    resizeSize = standardSize;
-                }
-            }
-
-            if (!resizePreset || shouldUsePreset(*resizePreset, preset)) {
-                resizePreset = &preset.get();
-                if (requestedWidth)
-                    resizeSize = { requestedWidth.value(), requestedWidth.value() * preset->size.height() / preset->size.width()};
-                else
-                    resizeSize = { requestedHeight.value() * preset->size.width() / preset->size.height(), requestedHeight.value() };
-            }
-        }
-    }
-
-    if (!exactSizePreset && !aspectRatioPreset && !resizePreset)
-        return { };
-
-    result.requestedFrameRate = requestedFrameRate.value();
-    if (exactSizePreset) {
-        result.encodingPreset = exactSizePreset;
-        result.requestedSize = exactSizePreset->size;
-        return result;
-    }
-
-    if (aspectRatioPreset) {
-        result.encodingPreset = aspectRatioPreset;
-        result.requestedSize = aspectRatioMatchSize;
-        return result;
-    }
-
-    result.encodingPreset = resizePreset;
-    result.requestedSize = resizeSize;
-    return result;
+    stop();
+    forEachObserver([](auto& observer) {
+        observer.sourceStopped();
+    });
 }
 
-void RealtimeVideoSource::setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate)
+void RealtimeVideoSource::videoSampleAvailable(MediaSample& sample)
 {
-    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER, SizeAndFrameRate { width, height, frameRate });
-
-    auto size = this->size();
-    if (!width && !height && !size.isEmpty()) {
-        width = size.width();
-        height = size.height();
-    }
-
-    Optional<RealtimeVideoSource::CaptureSizeAndFrameRate> match = bestSupportedSizeAndFrameRate(width, height, frameRate);
-    ASSERT(match);
-    if (!match)
+    if (!isProducingData())
         return;
 
-    setFrameRateWithPreset(match->requestedFrameRate, match->encodingPreset);
-
-    if (!match->requestedSize.isEmpty())
-        setSize(match->requestedSize);
-    setFrameRate(match->requestedFrameRate);
+    if (auto mediaSample = adaptVideoSample(sample))
+        RealtimeMediaSource::videoSampleAvailable(*mediaSample);
 }
 
-void RealtimeVideoSource::dispatchMediaSampleToObservers(MediaSample& sample)
+Ref<RealtimeMediaSource> RealtimeVideoSource::clone()
 {
-    MediaTime sampleTime = sample.outputPresentationTime();
-    if (!sampleTime || !sampleTime.isValid())
-        sampleTime = sample.presentationTime();
+    auto source = create(m_source.copyRef());
+    source->m_currentSettings = m_currentSettings;
 
-    auto frameTime = sampleTime.toDouble();
-    m_observedFrameTimeStamps.append(frameTime);
-    m_observedFrameTimeStamps.removeAllMatching([&](auto time) {
-        return time <= frameTime - 2;
-    });
-
-    auto interval = m_observedFrameTimeStamps.last() - m_observedFrameTimeStamps.first();
-    if (interval > 1)
-        m_observedFrameRate = (m_observedFrameTimeStamps.size() / interval);
-
-    auto mediaSample = makeRefPtr(&sample);
-#if PLATFORM(COCOA)
-    if (!isRemote()) {
-        auto size = this->size();
-        if (!size.isEmpty() && size != expandedIntSize(sample.presentationSize())) {
-
-            if (!m_imageTransferSession || m_imageTransferSession->pixelFormat() != sample.videoPixelFormat())
-                m_imageTransferSession = ImageTransferSessionVT::create(sample.videoPixelFormat());
-
-            if (m_imageTransferSession) {
-                mediaSample = m_imageTransferSession->convertMediaSample(sample, size);
-                if (!mediaSample) {
-                    ASSERT_NOT_REACHED();
-                    return;
-                }
-            }
-        }
-    }
-#endif
-
-    videoSampleAvailable(mediaSample.releaseNonNull());
+    return source;
 }
 
-#if !RELEASE_LOG_DISABLED
-Ref<JSON::Object> SizeAndFrameRate::toJSONObject() const
-{
-    auto object = JSON::Object::create();
-
-    object->setDouble("width"_s, width ? width.value() : 0);
-    object->setDouble("height"_s, height ? height.value() : 0);
-    object->setDouble("frameRate"_s, frameRate ? frameRate.value() : 0);
-
-    return object;
-}
-
-String SizeAndFrameRate::toJSONString() const
-{
-    return toJSONObject()->toJSONString();
-}
-#endif
-
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeVideoSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,93 +27,46 @@
 
 #if ENABLE(MEDIA_STREAM)
 
-#include "ImageBuffer.h"
-#include "MediaSample.h"
-#include "RealtimeMediaSource.h"
-#include "VideoPreset.h"
-#include <wtf/Lock.h>
-#include <wtf/RunLoop.h>
+#include "RealtimeVideoCaptureSource.h"
 
 namespace WebCore {
 
-class ImageTransferSessionVT;
-
-class RealtimeVideoSource : public RealtimeMediaSource {
+// FIXME: Make RealtimeVideoSource derive from RealtimeMediaSource directly.
+class RealtimeVideoSource final : public RealtimeVideoCaptureSource, public RealtimeMediaSource::Observer {
 public:
-    virtual ~RealtimeVideoSource();
+    static Ref<RealtimeVideoSource> create(Ref<RealtimeVideoCaptureSource>&& source) { return adoptRef(*new RealtimeVideoSource(WTFMove(source))); }
 
-protected:
-    RealtimeVideoSource(String&& name, String&& id, String&& hashSalt);
-
-    void prepareToProduceData();
-    bool supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>) override;
-    void setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>) override;
-
-    virtual void generatePresets() = 0;
-    virtual bool prefersPreset(VideoPreset&) { return true; }
-    virtual void setFrameRateWithPreset(double, RefPtr<VideoPreset>) { };
-    virtual bool canResizeVideoFrames() const { return false; }
-    bool shouldUsePreset(VideoPreset& current, VideoPreset& candidate);
-
-    void setSupportedPresets(const Vector<Ref<VideoPreset>>&);
-    void setSupportedPresets(Vector<VideoPresetData>&&);
-    const Vector<Ref<VideoPreset>>& presets();
-
-    bool frameRateRangeIncludesRate(const FrameRateRange&, double);
-
-    void updateCapabilities(RealtimeMediaSourceCapabilities&);
-
-    void setDefaultSize(const IntSize& size) { m_defaultSize = size; }
-
-    double observedFrameRate() const { return m_observedFrameRate; }
-
-    void dispatchMediaSampleToObservers(MediaSample&);
-    const Vector<IntSize>& standardVideoSizes();
-
 private:
-    struct CaptureSizeAndFrameRate {
-        RefPtr<VideoPreset> encodingPreset;
-        IntSize requestedSize;
-        double requestedFrameRate { 0 };
-    };
-    bool supportsCaptureSize(Optional<int>, Optional<int>, const Function<bool(const IntSize&)>&&);
-    Optional<CaptureSizeAndFrameRate> bestSupportedSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double>);
-    bool presetSupportsFrameRate(RefPtr<VideoPreset>, double);
+    explicit RealtimeVideoSource(Ref<RealtimeVideoCaptureSource>&&);
+    ~RealtimeVideoSource();
 
-#if !RELEASE_LOG_DISABLED
-    const char* logClassName() const override { return "RealtimeVideoSource"; }
-#endif
+    // RealtimeVideoCaptureSource
+    void startProducingData() final;
+    void stopProducingData() final;
+    bool supportsSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate) final;
+    void setSizeAndFrameRate(Optional<int> width, Optional<int> height, Optional<double> frameRate) final;
+    Ref<RealtimeMediaSource> clone() final;
 
-    Vector<Ref<VideoPreset>> m_presets;
-    Deque<double> m_observedFrameTimeStamps;
-    double m_observedFrameRate { 0 };
-    IntSize m_defaultSize;
-#if PLATFORM(COCOA)
-    std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;
-#endif
-};
+    const RealtimeMediaSourceCapabilities& capabilities() final { return m_source->capabilities(); }
+    const RealtimeMediaSourceSettings& settings() final { return m_currentSettings; }
+    void generatePresets() final { m_source->generatePresets(); }
+    bool isCaptureSource() const final { return m_source->isCaptureSource(); }
+    CaptureDevice::DeviceType deviceType() const final { return m_source->deviceType(); }
+    void monitorOrientation(OrientationNotifier& notifier) final { m_source->monitorOrientation(notifier); }
+    bool interrupted() const final { return m_source->interrupted(); }
 
-struct SizeAndFrameRate {
-    Optional<int> width;
-    Optional<int> height;
-    Optional<double> frameRate;
+    // Observer
+    void sourceMutedChanged() final;
+    void sourceSettingsChanged() final;
+    void sourceStopped() final;
+    bool preventSourceFromStopping() final;
+    void videoSampleAvailable(MediaSample&) final;
 
-    String toJSONString() const;
-    Ref<JSON::Object> toJSONObject() const;
+    Ref<RealtimeVideoCaptureSource> m_source;
+    RealtimeMediaSourceSettings m_currentSettings;
 };
 
 } // namespace WebCore
 
-namespace WTF {
-template<typename Type> struct LogArgument;
-template <>
-struct LogArgument<WebCore::SizeAndFrameRate> {
-    static String toString(const WebCore::SizeAndFrameRate& size)
-    {
-        return size.toJSONString();
-    }
-};
-}; // namespace WTF
-
 #endif // ENABLE(MEDIA_STREAM)
 

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp	2019-06-20 18:55:32 UTC (rev 246644)
@@ -126,7 +126,7 @@
 }
 
 GStreamerVideoCaptureSource::GStreamerVideoCaptureSource(String&& deviceID, String&& name, String&& hashSalt, const gchar *source_factory)
-    : RealtimeVideoSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
+    : RealtimeVideoCaptureSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
     , m_capturer(std::make_unique<GStreamerVideoCapturer>(source_factory))
 {
     initializeGStreamerDebug();
@@ -133,7 +133,7 @@
 }
 
 GStreamerVideoCaptureSource::GStreamerVideoCaptureSource(GStreamerCaptureDevice device, String&& hashSalt)
-    : RealtimeVideoSource(String { device.persistentId() }, String { device.label() }, WTFMove(hashSalt))
+    : RealtimeVideoCaptureSource(String { device.persistentId() }, String { device.label() }, WTFMove(hashSalt))
     , m_capturer(std::make_unique<GStreamerVideoCapturer>(device))
 {
     initializeGStreamerDebug();

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -24,11 +24,11 @@
 #if ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
 #include "CaptureDevice.h"
 #include "GStreamerVideoCapturer.h"
-#include "RealtimeVideoSource.h"
+#include "RealtimeVideoCaptureSource.h"
 
 namespace WebCore {
 
-class GStreamerVideoCaptureSource : public RealtimeVideoSource {
+class GStreamerVideoCaptureSource : public RealtimeVideoCaptureSource {
 public:
     static CaptureSourceOrError create(String&& deviceID, String&& hashSalt, const MediaConstraints*);
     WEBCORE_EXPORT static VideoCaptureFactory& factory();

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -29,7 +29,7 @@
 
 #include "IntSizeHash.h"
 #include "OrientationNotifier.h"
-#include "RealtimeVideoSource.h"
+#include "RealtimeVideoCaptureSource.h"
 #include <wtf/Lock.h>
 #include <wtf/text/StringHash.h>
 
@@ -51,7 +51,7 @@
 class AVVideoPreset;
 class ImageTransferSessionVT;
 
-class AVVideoCaptureSource : public RealtimeVideoSource, private OrientationNotifier::Observer {
+class AVVideoCaptureSource : public RealtimeVideoCaptureSource, private OrientationNotifier::Observer {
 public:
     static CaptureSourceOrError create(String&& id, String&& hashSalt, const MediaConstraints*);
 
@@ -91,6 +91,7 @@
     CaptureDevice::DeviceType deviceType() const final { return CaptureDevice::DeviceType::Camera; }
     bool interrupted() const final;
 
+    MediaSample::VideoRotation sampleRotation() const final { return m_sampleRotation; }
     void setFrameRateWithPreset(double, RefPtr<VideoPreset>) final;
     bool prefersPreset(VideoPreset&) final;
     void generatePresets() final;

Modified: trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm	2019-06-20 18:55:32 UTC (rev 246644)
@@ -37,6 +37,7 @@
 #import "PlatformLayer.h"
 #import "RealtimeMediaSourceCenter.h"
 #import "RealtimeMediaSourceSettings.h"
+#import "RealtimeVideoSource.h"
 #import "RealtimeVideoUtilities.h"
 #import <AVFoundation/AVCaptureDevice.h>
 #import <AVFoundation/AVCaptureInput.h>
@@ -121,11 +122,11 @@
             return WTFMove(result.value().badConstraint);
     }
 
-    return CaptureSourceOrError(WTFMove(source));
+    return CaptureSourceOrError(RealtimeVideoSource::create(WTFMove(source)));
 }
 
 AVVideoCaptureSource::AVVideoCaptureSource(AVCaptureDevice* device, String&& id, String&& hashSalt)
-    : RealtimeVideoSource(device.localizedName, WTFMove(id), WTFMove(hashSalt))
+    : RealtimeVideoCaptureSource(device.localizedName, WTFMove(id), WTFMove(hashSalt))
     , m_objcObserver(adoptNS([[WebCoreAVVideoCaptureSourceObserver alloc] initWithCallback:this]))
     , m_device(device)
 {
@@ -637,7 +638,6 @@
         captureFailed();
 }
 
-
 } // namespace WebCore
 
 @implementation WebCoreAVVideoCaptureSourceObserver

Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -59,6 +59,7 @@
 
     void orientationChanged(int orientation) final;
     void monitorOrientation(OrientationNotifier&) final;
+    MediaSample::VideoRotation sampleRotation() const final { return m_deviceOrientation; }
 
     MediaSample::VideoRotation m_deviceOrientation { MediaSample::VideoRotation::None };
     std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;

Modified: trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.mm (246643 => 246644)


--- trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.mm	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mediastream/mac/MockRealtimeVideoSourceMac.mm	2019-06-20 18:55:32 UTC (rev 246644)
@@ -41,6 +41,7 @@
 #import "NotImplemented.h"
 #import "PlatformLayer.h"
 #import "RealtimeMediaSourceSettings.h"
+#import "RealtimeVideoSource.h"
 #import "RealtimeVideoUtilities.h"
 #import <QuartzCore/CALayer.h>
 #import <QuartzCore/CATransaction.h>
@@ -66,7 +67,7 @@
     if (constraints && source->applyConstraints(*constraints))
         return { };
 
-    return CaptureSourceOrError(WTFMove(source));
+    return CaptureSourceOrError(RealtimeVideoSource::create(WTFMove(source)));
 }
 
 MockRealtimeVideoSourceMac::MockRealtimeVideoSourceMac(String&& deviceID, String&& name, String&& hashSalt)

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp (246643 => 246644)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp	2019-06-20 18:55:32 UTC (rev 246644)
@@ -42,6 +42,7 @@
 #include "NotImplemented.h"
 #include "PlatformLayer.h"
 #include "RealtimeMediaSourceSettings.h"
+#include "RealtimeVideoSource.h"
 #include <math.h>
 #include <wtf/UUID.h>
 #include <wtf/text/StringConcatenateNumbers.h>
@@ -62,12 +63,12 @@
     if (constraints && source->applyConstraints(*constraints))
         return { };
 
-    return CaptureSourceOrError(WTFMove(source));
+    return CaptureSourceOrError(RealtimeVideoSource::create(WTFMove(source)));
 }
 #endif
 
 MockRealtimeVideoSource::MockRealtimeVideoSource(String&& deviceID, String&& name, String&& hashSalt)
-    : RealtimeVideoSource(WTFMove(name), WTFMove(deviceID), WTFMove(hashSalt))
+    : RealtimeVideoCaptureSource(WTFMove(name), WTFMove(deviceID), WTFMove(hashSalt))
     , m_emitFrameTimer(RunLoop::current(), this, &MockRealtimeVideoSource::generateFrame)
 {
     auto device = MockRealtimeMediaSourceCenter::mockDeviceWithPersistentID(persistentID());
@@ -97,7 +98,7 @@
     // FIXME: consider splitting mock display into another class so we don't don't have to do this silly dance
     // because of the RealtimeVideoSource inheritance.
     if (mockCamera())
-        return RealtimeVideoSource::supportsSizeAndFrameRate(width, height, rate);
+        return RealtimeVideoCaptureSource::supportsSizeAndFrameRate(width, height, rate);
 
     return RealtimeMediaSource::supportsSizeAndFrameRate(width, height, rate);
 }
@@ -107,7 +108,7 @@
     // FIXME: consider splitting mock display into another class so we don't don't have to do this silly dance
     // because of the RealtimeVideoSource inheritance.
     if (mockCamera()) {
-        RealtimeVideoSource::setSizeAndFrameRate(width, height, rate);
+        RealtimeVideoCaptureSource::setSizeAndFrameRate(width, height, rate);
         return;
     }
 

Modified: trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h (246643 => 246644)


--- trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2019-06-20 18:28:22 UTC (rev 246643)
+++ trunk/Source/WebCore/platform/mock/MockRealtimeVideoSource.h	2019-06-20 18:55:32 UTC (rev 246644)
@@ -37,7 +37,7 @@
 #include "ImageBuffer.h"
 #include "MockMediaDevice.h"
 #include "RealtimeMediaSourceFactory.h"
-#include "RealtimeVideoSource.h"
+#include "RealtimeVideoCaptureSource.h"
 #include <wtf/RunLoop.h>
 
 namespace WebCore {
@@ -45,7 +45,7 @@
 class FloatRect;
 class GraphicsContext;
 
-class MockRealtimeVideoSource : public RealtimeVideoSource {
+class MockRealtimeVideoSource : public RealtimeVideoCaptureSource {
 public:
 
     static CaptureSourceOrError create(String&& deviceID, String&& name, String&& hashSalt, const MediaConstraints*);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to