Title: [265328] trunk
Revision
265328
Author
you...@apple.com
Date
2020-08-06 08:25:39 -0700 (Thu, 06 Aug 2020)

Log Message

Add support for MediaRecorder bitrate options
https://bugs.webkit.org/show_bug.cgi?id=214973

Reviewed by Eric Carlson.

Source/WebCore:

Pipe options to MediaRecorderPrivate constructor.
For the actual implementation, pass it down to VideoSampleBufferCompressor and AudioSampleBufferCompressor.
For AudioSampleBufferCompressor, we do not handle well some bit rates, so for now, we limit to specific values.

Tests: http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html
       http/wpt/mediarecorder/MediaRecorder-video-bitrate.html

* Modules/mediarecorder/MediaRecorder.cpp:
(WebCore::MediaRecorder::create):
(WebCore::MediaRecorder::createMediaRecorderPrivate):
(WebCore::MediaRecorder::MediaRecorder):
(WebCore::MediaRecorder::startRecording):
* Modules/mediarecorder/MediaRecorder.h:
* Modules/mediarecorder/MediaRecorderProvider.cpp:
(WebCore::MediaRecorderProvider::createMediaRecorderPrivate):
* Modules/mediarecorder/MediaRecorderProvider.h:
* WebCore.xcodeproj/project.pbxproj:
* loader/EmptyClients.cpp:
* platform/mediarecorder/MediaRecorderPrivate.h:
* platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
(WebCore::MediaRecorderPrivateAVFImpl::create):
* platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:
* platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h:
* platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm:
(WebCore::AudioSampleBufferCompressor::setBitsPerSecond):
(WebCore::AudioSampleBufferCompressor::outputBitRate const):
(WebCore::AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription):
Do not exit when not able to set bitrate as we still want to set m_maxOutputPacketSize.
In case of error in setting up the converter, clean it up so that we do not use a partially set up converter.
* platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
* platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:
(WebCore::MediaRecorderPrivateWriter::create):
(WebCore::MediaRecorderPrivateWriter::setOptions):
* platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h:
* platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:
(WebCore::VideoSampleBufferCompressor::setBitsPerSecond):
(WebCore::setCompressionSessionProperty):
(WebCore::VideoSampleBufferCompressor::initCompressionSession):
* testing/Internals.cpp:
(WebCore::createRecorderMockSource):

Source/WebKit:

Serialize options when creating remote media recorder.

* GPUProcess/webrtc/RemoteMediaRecorder.cpp:
(WebKit::RemoteMediaRecorder::create):
* GPUProcess/webrtc/RemoteMediaRecorder.h:
* GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
(WebKit::RemoteMediaRecorderManager::createRecorder):
* GPUProcess/webrtc/RemoteMediaRecorderManager.h:
* GPUProcess/webrtc/RemoteMediaRecorderManager.messages.in:
* WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp:
(WebKit::MediaRecorderPrivate::MediaRecorderPrivate):
(WebKit::MediaRecorderPrivate::startRecording):
* WebProcess/GPU/webrtc/MediaRecorderPrivate.h:
* WebProcess/GPU/webrtc/MediaRecorderProvider.cpp:
(WebKit::MediaRecorderProvider::createMediaRecorderPrivate):
* WebProcess/GPU/webrtc/MediaRecorderProvider.h:

LayoutTests:

* http/wpt/mediarecorder/MediaRecorder-audio-bitrate-expected.txt: Added.
* http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html: Added.
* http/wpt/mediarecorder/MediaRecorder-video-bitrate-expected.txt: Added.
* http/wpt/mediarecorder/MediaRecorder-video-bitrate.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (265327 => 265328)


--- trunk/LayoutTests/ChangeLog	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/LayoutTests/ChangeLog	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1,3 +1,15 @@
+2020-08-06  Youenn Fablet  <you...@apple.com>
+
+        Add support for MediaRecorder bitrate options
+        https://bugs.webkit.org/show_bug.cgi?id=214973
+
+        Reviewed by Eric Carlson.
+
+        * http/wpt/mediarecorder/MediaRecorder-audio-bitrate-expected.txt: Added.
+        * http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html: Added.
+        * http/wpt/mediarecorder/MediaRecorder-video-bitrate-expected.txt: Added.
+        * http/wpt/mediarecorder/MediaRecorder-video-bitrate.html: Added.
+
 2020-08-06  Simon Fraser  <simon.fra...@apple.com>
 
         Scrolling tree nodes sometimes don't match layer z-order

Added: trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate-expected.txt (0 => 265328)


--- trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate-expected.txt	2020-08-06 15:25:39 UTC (rev 265328)
@@ -0,0 +1,3 @@
+
+PASS Various audio bitrates 
+

Added: trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html (0 => 265328)


--- trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html	2020-08-06 15:25:39 UTC (rev 265328)
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+<head>
+    <title>MediaRecorder audio bitrate</title>
+    <script src=""
+    <script src=""
+</head>
+<body>
+<script>
+    async function record(stream, bitRate)
+    {
+        const recorder = new MediaRecorder(stream, { audioBitsPerSecond : bitRate });
+        const promise = new Promise((resolve, reject) => {
+            recorder._ondataavailable_ = (e) => resolve(e.data);
+            setTimeout(reject, 5000);
+        });
+        recorder.start();
+        setTimeout(() => recorder.stop(), 2500);
+        return promise;
+    }
+
+    promise_test(async (t) => {
+        const stream = await navigator.mediaDevices.getUserMedia({ audio : true });
+        const bitRates = [128000, 192000, 256000];
+        let promises = [];
+        bitRates.forEach(bitRate => {
+            promises.push(record(stream, bitRate));
+        });
+
+        let blobs = [0, 0, 0];
+        promises.forEach(async (promise, index) => {
+            blobs[index] = await promise;
+        });
+        await Promise.all(promises);
+        assert_not_equals(blobs[0].size, 0);
+        assert_greater_than(blobs[2].size, blobs[0].size);
+    }, "Various audio bitrates");
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate-expected.txt (0 => 265328)


--- trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate-expected.txt	2020-08-06 15:25:39 UTC (rev 265328)
@@ -0,0 +1,3 @@
+
+PASS Various video bitrates 
+

Added: trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate.html (0 => 265328)


--- trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/mediarecorder/MediaRecorder-video-bitrate.html	2020-08-06 15:25:39 UTC (rev 265328)
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+<head>
+    <title>MediaRecorder video bitrate</title>
+    <script src=""
+    <script src=""
+</head>
+<body>
+<script>
+    async function record(bitRate)
+    {
+        const stream = await navigator.mediaDevices.getUserMedia({ video : { width : 1024 } });
+        const recorder = new MediaRecorder(stream, { videoBitsPerSecond : bitRate });
+        const promise = new Promise((resolve, reject) => {
+            let count = 0;
+            let blobs = [];
+            recorder._ondataavailable_ = (e) => resolve(e.data);
+            setTimeout(() => reject("datavailable event timed out"), 15000);
+        });
+        recorder.start();
+        setTimeout(() => recorder.stop(), 1000);
+        return promise;
+    }
+
+    promise_test(async (t) => {
+        let blobs = [0, 0];
+        blobs[0] = await record(50000);
+        blobs[1] = await record(5000000);
+
+        // We are taking the second blob since it might be more accurate than the first one.
+        assert_greater_than(blobs[0].size, 0, "blob0");
+        assert_greater_than(blobs[1].size, blobs[0].size, "blob2");
+    }, "Various video bitrates");
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (265327 => 265328)


--- trunk/Source/WebCore/ChangeLog	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/ChangeLog	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1,3 +1,51 @@
+2020-08-06  Youenn Fablet  <you...@apple.com>
+
+        Add support for MediaRecorder bitrate options
+        https://bugs.webkit.org/show_bug.cgi?id=214973
+
+        Reviewed by Eric Carlson.
+
+        Pipe options to MediaRecorderPrivate constructor.
+        For the actual implementation, pass it down to VideoSampleBufferCompressor and AudioSampleBufferCompressor.
+        For AudioSampleBufferCompressor, we do not handle well some bit rates, so for now, we limit to specific values.
+
+        Tests: http/wpt/mediarecorder/MediaRecorder-audio-bitrate.html
+               http/wpt/mediarecorder/MediaRecorder-video-bitrate.html
+
+        * Modules/mediarecorder/MediaRecorder.cpp:
+        (WebCore::MediaRecorder::create):
+        (WebCore::MediaRecorder::createMediaRecorderPrivate):
+        (WebCore::MediaRecorder::MediaRecorder):
+        (WebCore::MediaRecorder::startRecording):
+        * Modules/mediarecorder/MediaRecorder.h:
+        * Modules/mediarecorder/MediaRecorderProvider.cpp:
+        (WebCore::MediaRecorderProvider::createMediaRecorderPrivate):
+        * Modules/mediarecorder/MediaRecorderProvider.h:
+        * WebCore.xcodeproj/project.pbxproj:
+        * loader/EmptyClients.cpp:
+        * platform/mediarecorder/MediaRecorderPrivate.h:
+        * platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
+        (WebCore::MediaRecorderPrivateAVFImpl::create):
+        * platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:
+        * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h:
+        * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm:
+        (WebCore::AudioSampleBufferCompressor::setBitsPerSecond):
+        (WebCore::AudioSampleBufferCompressor::outputBitRate const):
+        (WebCore::AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription):
+        Do not exit when not able to set bitrate as we still want to set m_maxOutputPacketSize.
+        In case of error in setting up the converter, clean it up so that we do not use a partially set up converter.
+        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
+        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:
+        (WebCore::MediaRecorderPrivateWriter::create):
+        (WebCore::MediaRecorderPrivateWriter::setOptions):
+        * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h:
+        * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:
+        (WebCore::VideoSampleBufferCompressor::setBitsPerSecond):
+        (WebCore::setCompressionSessionProperty):
+        (WebCore::VideoSampleBufferCompressor::initCompressionSession):
+        * testing/Internals.cpp:
+        (WebCore::createRecorderMockSource):
+
 2020-08-06  Simon Fraser  <simon.fra...@apple.com>
 
         Scrolling tree nodes sometimes don't match layer z-order

Modified: trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp (265327 => 265328)


--- trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -48,9 +48,10 @@
 
 ExceptionOr<Ref<MediaRecorder>> MediaRecorder::create(Document& document, Ref<MediaStream>&& stream, Options&& options)
 {
-    auto privateInstance = MediaRecorder::createMediaRecorderPrivate(document, stream->privateStream());
-    if (!privateInstance)
-        return Exception { NotSupportedError, "The MediaRecorder is unsupported on this platform"_s };
+    auto result = MediaRecorder::createMediaRecorderPrivate(document, stream->privateStream(), options);
+    if (result.hasException())
+        return result.releaseException();
+
     auto recorder = adoptRef(*new MediaRecorder(document, WTFMove(stream), WTFMove(options)));
     recorder->suspendIfNeeded();
     return recorder;
@@ -61,27 +62,27 @@
     m_customCreator = creator;
 }
 
-std::unique_ptr<MediaRecorderPrivate> MediaRecorder::createMediaRecorderPrivate(Document& document, MediaStreamPrivate& stream)
+ExceptionOr<std::unique_ptr<MediaRecorderPrivate>> MediaRecorder::createMediaRecorderPrivate(Document& document, MediaStreamPrivate& stream, const Options& options)
 {
     if (m_customCreator)
-        return m_customCreator(stream);
+        return m_customCreator(stream, options);
 
 #if PLATFORM(COCOA)
     auto* page = document.page();
     if (!page)
-        return nullptr;
+        return Exception { InvalidStateError };
 
-    return page->mediaRecorderProvider().createMediaRecorderPrivate(stream);
+    return page->mediaRecorderProvider().createMediaRecorderPrivate(stream, options);
 #else
     UNUSED_PARAM(document);
     UNUSED_PARAM(stream);
-    return nullptr;
+    return Exception { NotSupportedError, "The MediaRecorder is unsupported on this platform"_s };
 #endif
 }
 
-MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, Options&& option)
+MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, Options&& options)
     : ActiveDOMObject(document)
-    , m_options(WTFMove(option))
+    , m_options(WTFMove(options))
     , m_stream(WTFMove(stream))
     , m_timeSliceTimer([this] { requestData(); })
 {
@@ -135,11 +136,13 @@
         return Exception { InvalidStateError, "The MediaRecorder's state must be inactive in order to start recording"_s };
 
     ASSERT(!m_private);
-    m_private = createMediaRecorderPrivate(*document(), m_stream->privateStream());
+    auto result = createMediaRecorderPrivate(*document(), m_stream->privateStream(), m_options);
 
-    if (!m_private)
-        return Exception { NotSupportedError, "The MediaRecorder is unsupported on this platform"_s };
+    ASSERT(!result.hasException());
+    if (result.hasException())
+        return result.releaseException();
 
+    m_private = result.releaseReturnValue();
     m_private->startRecording([this, pendingActivity = makePendingActivity(*this)](auto&& exception) mutable {
         if (!m_isActive)
             return;

Modified: trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.h (265327 => 265328)


--- trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -28,6 +28,8 @@
 
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
+#include "ExceptionOr.h"
+#include "MediaRecorderPrivateOptions.h"
 #include "MediaStream.h"
 #include "MediaStreamTrackPrivate.h"
 #include "Timer.h"
@@ -49,18 +51,12 @@
 public:
     enum class RecordingState { Inactive, Recording, Paused };
     
-    struct Options {
-        String mimeType;
-        unsigned audioBitsPerSecond;
-        unsigned videoBitsPerSecond;
-        unsigned bitsPerSecond;
-    };
-    
     ~MediaRecorder();
     
+    using Options = MediaRecorderPrivateOptions;
     static ExceptionOr<Ref<MediaRecorder>> create(Document&, Ref<MediaStream>&&, Options&& = { });
     
-    using CreatorFunction = std::unique_ptr<MediaRecorderPrivate>(*)(MediaStreamPrivate&);
+    using CreatorFunction = ExceptionOr<std::unique_ptr<MediaRecorderPrivate>> (*)(MediaStreamPrivate&, const Options&);
 
     WEBCORE_EXPORT static void setCustomPrivateRecorderCreator(CreatorFunction);
     
@@ -76,9 +72,9 @@
     MediaStream& stream() { return m_stream.get(); }
 
 private:
-    MediaRecorder(Document&, Ref<MediaStream>&&, Options&& = { });
+    MediaRecorder(Document&, Ref<MediaStream>&&, Options&&);
 
-    static std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(Document&, MediaStreamPrivate&);
+    static ExceptionOr<std::unique_ptr<MediaRecorderPrivate>> createMediaRecorderPrivate(Document&, MediaStreamPrivate&, const Options&);
     
     Document* document() const;
 
@@ -111,7 +107,7 @@
     void trackEnabledChanged(MediaStreamTrackPrivate&) final { };
 
     static CreatorFunction m_customCreator;
-    
+
     Options m_options;
     Ref<MediaStream> m_stream;
     std::unique_ptr<MediaRecorderPrivate> m_private;

Modified: trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.cpp (265327 => 265328)


--- trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -32,12 +32,13 @@
 
 namespace WebCore {
 
-std::unique_ptr<MediaRecorderPrivate> MediaRecorderProvider::createMediaRecorderPrivate(MediaStreamPrivate& stream)
+std::unique_ptr<MediaRecorderPrivate> MediaRecorderProvider::createMediaRecorderPrivate(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions& options)
 {
 #if HAVE(AVASSETWRITERDELEGATE)
-    return MediaRecorderPrivateAVFImpl::create(stream);
+    return MediaRecorderPrivateAVFImpl::create(stream, options);
 #else
     UNUSED_PARAM(stream);
+    UNUSED_PARAM(options);
     return nullptr;
 #endif
 }

Modified: trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.h (265327 => 265328)


--- trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -29,6 +29,7 @@
 
 class MediaRecorderPrivate;
 class MediaStreamPrivate;
+struct MediaRecorderPrivateOptions;
 
 class WEBCORE_EXPORT MediaRecorderProvider {
     WTF_MAKE_FAST_ALLOCATED;
@@ -37,7 +38,7 @@
     virtual ~MediaRecorderProvider() = default;
 
 #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
-    virtual std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(MediaStreamPrivate&);
+    virtual std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(MediaStreamPrivate&, const MediaRecorderPrivateOptions&);
 #endif
 
     void setUseGPUProcess(bool value) { m_useGPUProcess = value; }

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (265327 => 265328)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1052,6 +1052,7 @@
 		413E00791DB0E4F2002341D2 /* MemoryRelease.h in Headers */ = {isa = PBXBuildFile; fileRef = 413E00781DB0E4DE002341D2 /* MemoryRelease.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		414460A22412994500814BE7 /* MediaSessionIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 414460A02412994100814BE7 /* MediaSessionIdentifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		414598C223C8D177002B9CC8 /* LocalSampleBufferDisplayLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 414598C123C8AD79002B9CC8 /* LocalSampleBufferDisplayLayer.mm */; };
+		414B7FAD24D81CC10033D442 /* MediaRecorderPrivateOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 414B7FAB24D81C8F0033D442 /* MediaRecorderPrivateOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		414B82051D6DF0E50077EBE3 /* StructuredClone.h in Headers */ = {isa = PBXBuildFile; fileRef = 414B82031D6DF0D90077EBE3 /* StructuredClone.h */; };
 		414DEDE71F9FE91E0047C40D /* EmptyFrameLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 414DEDE51F9FE9150047C40D /* EmptyFrameLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		415071581685067300C3C7B3 /* SelectorFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 415071561685067300C3C7B3 /* SelectorFilter.h */; };
@@ -7475,6 +7476,7 @@
 		414AD40021498D3100521676 /* RTCRtpDecodingParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RTCRtpDecodingParameters.h; sourceTree = "<group>"; };
 		414AD40121498D3100521676 /* RTCRtpDecodingParameters.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RTCRtpDecodingParameters.idl; sourceTree = "<group>"; };
 		414AD40221498D3200521676 /* RTCRtpCodingParameters.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RTCRtpCodingParameters.idl; sourceTree = "<group>"; };
+		414B7FAB24D81C8F0033D442 /* MediaRecorderPrivateOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaRecorderPrivateOptions.h; sourceTree = "<group>"; };
 		414B82021D6DF0D90077EBE3 /* StructuredClone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructuredClone.cpp; sourceTree = "<group>"; };
 		414B82031D6DF0D90077EBE3 /* StructuredClone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructuredClone.h; sourceTree = "<group>"; };
 		414DEDE51F9FE9150047C40D /* EmptyFrameLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmptyFrameLoaderClient.h; sourceTree = "<group>"; };
@@ -19554,6 +19556,7 @@
 				4D73F944218BC5FA003A3ED6 /* MediaRecorderPrivateAVFImpl.h */,
 				4D9F6B652182532B0092A9C5 /* MediaRecorderPrivateMock.cpp */,
 				4D9F6B642182532B0092A9C5 /* MediaRecorderPrivateMock.h */,
+				414B7FAB24D81C8F0033D442 /* MediaRecorderPrivateOptions.h */,
 			);
 			path = mediarecorder;
 			sourceTree = "<group>";
@@ -32568,6 +32571,7 @@
 				4DB7130D216ECB4D0096A4DD /* MediaRecorderErrorEvent.h in Headers */,
 				4D3B5016217E58B700665DB1 /* MediaRecorderPrivate.h in Headers */,
 				4D73F946218BC5FA003A3ED6 /* MediaRecorderPrivateAVFImpl.h in Headers */,
+				414B7FAD24D81CC10033D442 /* MediaRecorderPrivateOptions.h in Headers */,
 				4D73F94E218C4A87003A3ED6 /* MediaRecorderPrivateWriterCocoa.h in Headers */,
 				4176E89623C3537B003E83FE /* MediaRecorderProvider.h in Headers */,
 				C90843D01B18E47D00B68564 /* MediaRemoteControls.h in Headers */,

Modified: trunk/Source/WebCore/loader/EmptyClients.cpp (265327 => 265328)


--- trunk/Source/WebCore/loader/EmptyClients.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/loader/EmptyClients.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -588,7 +588,7 @@
     EmptyMediaRecorderProvider() = default;
 private:
 #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
-    std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(MediaStreamPrivate&) final { return nullptr; }
+    std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(MediaStreamPrivate&, const MediaRecorderPrivateOptions&) final { return nullptr; }
 #endif
 };
 

Modified: trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -27,6 +27,7 @@
 #include <wtf/CompletionHandler.h>
 #include <wtf/Forward.h>
 #include "Exception.h"
+#include "MediaRecorderPrivateOptions.h"
 #include "RealtimeMediaSource.h"
 
 #if ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -37,7 +37,7 @@
 
 namespace WebCore {
 
-std::unique_ptr<MediaRecorderPrivateAVFImpl> MediaRecorderPrivateAVFImpl::create(MediaStreamPrivate& stream)
+std::unique_ptr<MediaRecorderPrivateAVFImpl> MediaRecorderPrivateAVFImpl::create(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions& options)
 {
     // FIXME: we will need to implement support for multiple audio/video tracks
     // Currently we only choose the first track as the recorded track.
@@ -45,11 +45,11 @@
 
     auto selectedTracks = MediaRecorderPrivate::selectTracks(stream);
 
-    auto writer = MediaRecorderPrivateWriter::create(!!selectedTracks.audioTrack, !!selectedTracks.videoTrack);
+    auto writer = MediaRecorderPrivateWriter::create(!!selectedTracks.audioTrack, !!selectedTracks.videoTrack, options);
     if (!writer)
         return nullptr;
 
-    auto recorder = makeUnique<MediaRecorderPrivateAVFImpl>(writer.releaseNonNull());
+    auto recorder = std::unique_ptr<MediaRecorderPrivateAVFImpl>(new MediaRecorderPrivateAVFImpl(writer.releaseNonNull()));
     if (selectedTracks.audioTrack)
         recorder->setAudioSource(&selectedTracks.audioTrack->source());
     if (selectedTracks.videoTrack)

Modified: trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -37,12 +37,12 @@
     : public MediaRecorderPrivate {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static std::unique_ptr<MediaRecorderPrivateAVFImpl> create(MediaStreamPrivate&);
+    static std::unique_ptr<MediaRecorderPrivateAVFImpl> create(MediaStreamPrivate&, const MediaRecorderPrivateOptions&);
+    ~MediaRecorderPrivateAVFImpl();
 
+private:
     explicit MediaRecorderPrivateAVFImpl(Ref<MediaRecorderPrivateWriter>&&);
-    ~MediaRecorderPrivateAVFImpl();
 
-private:
     // MediaRecorderPrivate
     void videoSampleAvailable(MediaSample&) final;
     void fetchData(FetchDataCallback&&) final;

Added: trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateOptions.h (0 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateOptions.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateOptions.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 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. AND ITS 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 APPLE INC. OR ITS 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
+
+#include <wtf/Forward.h>
+
+#if ENABLE(MEDIA_STREAM)
+
+namespace WebCore {
+
+struct MediaRecorderPrivateOptions {
+    String mimeType;
+    Optional<unsigned> audioBitsPerSecond;
+    Optional<unsigned> videoBitsPerSecond;
+    Optional<unsigned> bitsPerSecond;
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static Optional<MediaRecorderPrivateOptions> decode(Decoder&);
+};
+
+template<class Encoder>
+inline void MediaRecorderPrivateOptions::encode(Encoder& encoder) const
+{
+    encoder << mimeType;
+    encoder << audioBitsPerSecond;
+    encoder << videoBitsPerSecond;
+    encoder << bitsPerSecond;
+}
+
+template<class Decoder>
+inline Optional<MediaRecorderPrivateOptions> MediaRecorderPrivateOptions::decode(Decoder& decoder)
+{
+    String mimeType;
+    if (!decoder.decode(mimeType))
+        return WTF::nullopt;
+
+    Optional<Optional<unsigned>> audioBitsPerSecond;
+    decoder >> audioBitsPerSecond;
+    if (!audioBitsPerSecond)
+        return WTF::nullopt;
+
+    Optional<Optional<unsigned>> videoBitsPerSecond;
+    decoder >> videoBitsPerSecond;
+    if (!videoBitsPerSecond)
+        return WTF::nullopt;
+
+    Optional<Optional<unsigned>> bitsPerSecond;
+    decoder >> bitsPerSecond;
+    if (!bitsPerSecond)
+        return WTF::nullopt;
+
+    return MediaRecorderPrivateOptions { WTFMove(mimeType), *audioBitsPerSecond, *videoBitsPerSecond, *bitsPerSecond };
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -39,6 +39,7 @@
     static std::unique_ptr<AudioSampleBufferCompressor> create(CMBufferQueueTriggerCallback, void* callbackObject);
     ~AudioSampleBufferCompressor();
 
+    void setBitsPerSecond(unsigned);
     void finish();
     void addSampleBuffer(CMSampleBufferRef);
     CMSampleBufferRef getOutputSampleBuffer();
@@ -47,6 +48,7 @@
 private:
     AudioSampleBufferCompressor();
     bool initialize(CMBufferQueueTriggerCallback, void* callbackObject);
+    UInt32 outputBitRate(const AudioStreamBasicDescription&) const;
 
     static OSStatus audioConverterComplexInputDataProc(AudioConverterRef, UInt32*, AudioBufferList*, AudioStreamPacketDescription**, void*);
 
@@ -85,6 +87,7 @@
     size_t m_sampleBlockBufferSize { 0 };
     size_t m_currentOffsetInSampleBlockBuffer { 0 };
     AudioFormatID m_outputCodecType { kAudioFormatMPEG4AAC };
+    Optional<unsigned> m_outputBitRate;
 };
 
 }

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm	2020-08-06 15:25:39 UTC (rev 265328)
@@ -32,6 +32,8 @@
 #include <AudioToolbox/AudioConverter.h>
 #include <AudioToolbox/AudioFormat.h>
 #include <Foundation/Foundation.h>
+#include <algorithm>
+#include <wtf/Scope.h>
 
 #import <pal/cf/AudioToolboxSoftLink.h>
 
@@ -95,6 +97,34 @@
     });
 }
 
+void AudioSampleBufferCompressor::setBitsPerSecond(unsigned bitRate)
+{
+    // FIXME: we have some issues when setting up some bit rates, only allow some that work for the moment.
+    if (bitRate < 128000) {
+        RELEASE_LOG_INFO(WebRTC, "AudioSampleBufferCompressor::outputBitRate clamped to 128000.");
+        bitRate = 128000;
+    } else if (bitRate > 256000) {
+        RELEASE_LOG_INFO(WebRTC, "AudioSampleBufferCompressor::outputBitRate clamped to 256000.");
+        bitRate = 256000;
+    } else if (bitRate != 128000 && bitRate != 192000 && bitRate != 256000) {
+        RELEASE_LOG_INFO(WebRTC, "AudioSampleBufferCompressor::outputBitRate did not set output bit rate as value is not supported.");
+        return;
+    }
+    m_outputBitRate = bitRate;
+}
+
+UInt32 AudioSampleBufferCompressor::outputBitRate(const AudioStreamBasicDescription& destinationFormat) const
+{
+    if (m_outputBitRate)
+        return *m_outputBitRate;
+
+    if (destinationFormat.mSampleRate >= 44100)
+        return 192000;
+    if (destinationFormat.mSampleRate < 22000)
+        return 32000;
+    return 64000;
+}
+
 bool AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription(CMFormatDescriptionRef formatDescription, AudioFormatID outputFormatID)
 {
     const auto *audioFormatListItem = CMAudioFormatDescriptionGetRichestDecodableFormat(formatDescription);
@@ -118,6 +148,11 @@
     }
     m_converter = converter;
 
+    auto cleanupInCaseOfError = makeScopeExit([&] {
+        AudioConverterDispose(m_converter);
+        m_converter = nullptr;
+    });
+
     size_t cookieSize = 0;
     const void *cookie = CMAudioFormatDescriptionGetMagicCookie(formatDescription, &cookieSize);
     if (cookieSize) {
@@ -145,18 +180,10 @@
     }
 
     if (m_destinationFormat.mFormatID == kAudioFormatMPEG4AAC) {
-        // FIXME: Set outputBitRate according MediaRecorderOptions.audioBitsPerSecond.
-        UInt32 outputBitRate = 64000;
-        if (m_destinationFormat.mSampleRate >= 44100)
-            outputBitRate = 192000;
-        else if (m_destinationFormat.mSampleRate < 22000)
-            outputBitRate = 32000;
-
+        auto outputBitRate = this->outputBitRate(m_destinationFormat);
         size = sizeof(outputBitRate);
-        if (auto error = AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, size, &outputBitRate)) {
+        if (auto error = AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, size, &outputBitRate))
             RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor setting kAudioConverterEncodeBitRate failed with %d", error);
-            return false;
-        }
     }
 
     if (!m_destinationFormat.mBytesPerPacket) {
@@ -169,6 +196,8 @@
         }
     }
 
+    cleanupInCaseOfError.release();
+
     auto destinationBufferSize = computeBufferSizeForAudioFormat(m_destinationFormat, m_maxOutputPacketSize, LOW_WATER_TIME_IN_SECONDS);
     if (m_destinationBuffer.size() < destinationBufferSize)
         m_destinationBuffer.resize(destinationBufferSize);
@@ -428,8 +457,10 @@
         m_currentOutputPresentationTimeStamp = CMSampleBufferGetOutputPresentationTimeStamp(buffer);
 
         auto formatDescription = CMSampleBufferGetFormatDescription(buffer);
-        if (!initAudioConverterForSourceFormatDescription(formatDescription, m_outputCodecType))
+        if (!initAudioConverterForSourceFormatDescription(formatDescription, m_outputCodecType)) {
+            // FIXME: Maybe we should error the media recorder if we are not able to get a correct converter.
             return;
+        }
     }
 
     while (CMTIME_IS_INVALID(lowWaterTime) || CMTIME_COMPARE_INLINE(lowWaterTime, <, CMBufferQueueGetDuration(m_inputBufferQueue.get()))) {

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -59,10 +59,11 @@
 class MediaStreamTrackPrivate;
 class PlatformAudioData;
 class VideoSampleBufferCompressor;
+struct MediaRecorderPrivateOptions;
 
 class WEBCORE_EXPORT MediaRecorderPrivateWriter : public ThreadSafeRefCounted<MediaRecorderPrivateWriter, WTF::DestructionThread::Main>, public CanMakeWeakPtr<MediaRecorderPrivateWriter, WeakPtrFactoryInitialization::Eager> {
 public:
-    static RefPtr<MediaRecorderPrivateWriter> create(bool hasAudio, bool hasVideo);
+    static RefPtr<MediaRecorderPrivateWriter> create(bool hasAudio, bool hasVideo, const MediaRecorderPrivateOptions&);
     ~MediaRecorderPrivateWriter();
 
     void appendVideoSampleBuffer(CMSampleBufferRef);
@@ -78,6 +79,7 @@
     void clear();
 
     bool initialize();
+    void setOptions(const MediaRecorderPrivateOptions&);
 
     static void compressedVideoOutputBufferCallback(void*, CMBufferQueueTriggerToken);
     static void compressedAudioOutputBufferCallback(void*, CMBufferQueueTriggerToken);

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "AudioSampleBufferCompressor.h"
 #include "AudioStreamDescription.h"
 #include "Logging.h"
+#include "MediaRecorderPrivateOptions.h"
 #include "MediaStreamTrackPrivate.h"
 #include "VideoSampleBufferCompressor.h"
 #include "WebAudioBufferList.h"
@@ -114,11 +115,12 @@
 
 using namespace PAL;
 
-RefPtr<MediaRecorderPrivateWriter> MediaRecorderPrivateWriter::create(bool hasAudio, bool hasVideo)
+RefPtr<MediaRecorderPrivateWriter> MediaRecorderPrivateWriter::create(bool hasAudio, bool hasVideo, const MediaRecorderPrivateOptions& options)
 {
     auto writer = adoptRef(*new MediaRecorderPrivateWriter(hasAudio, hasVideo));
     if (!writer->initialize())
         return nullptr;
+    writer->setOptions(options);
     return writer;
 }
 
@@ -176,6 +178,14 @@
     return true;
 }
 
+void MediaRecorderPrivateWriter::setOptions(const MediaRecorderPrivateOptions& options)
+{
+    if (options.audioBitsPerSecond && m_audioCompressor)
+        m_audioCompressor->setBitsPerSecond(*options.audioBitsPerSecond);
+    if (options.videoBitsPerSecond && m_videoCompressor)
+        m_videoCompressor->setBitsPerSecond(*options.videoBitsPerSecond);
+}
+
 void MediaRecorderPrivateWriter::processNewCompressedVideoSampleBuffers()
 {
     ASSERT(m_hasVideo);

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -40,6 +40,7 @@
     static std::unique_ptr<VideoSampleBufferCompressor> create(CMVideoCodecType, CMBufferQueueTriggerCallback, void* callbackObject);
     ~VideoSampleBufferCompressor();
 
+    void setBitsPerSecond(unsigned);
     void finish();
     void addSampleBuffer(CMSampleBufferRef);
     CMSampleBufferRef getOutputSampleBuffer();
@@ -64,6 +65,7 @@
     bool m_isEncoding { false };
     float m_maxKeyFrameIntervalDuration { 2.0 };
     unsigned m_expectedFrameRate { 30 };
+    Optional<unsigned> m_outputBitRate;
 };
 
 }

Modified: trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm (265327 => 265328)


--- trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm	2020-08-06 15:25:39 UTC (rev 265328)
@@ -76,6 +76,11 @@
     return true;
 }
 
+void VideoSampleBufferCompressor::setBitsPerSecond(unsigned bitRate)
+{
+    m_outputBitRate = bitRate;
+}
+
 void VideoSampleBufferCompressor::finish()
 {
     dispatch_sync(m_serialDispatchQueue, ^{
@@ -101,6 +106,15 @@
     RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor CMBufferQueueEnqueue failed with %d", error);
 }
 
+static inline OSStatus setCompressionSessionProperty(VTCompressionSessionRef vtSession, CFStringRef key, uint32_t value)
+{
+    int64_t value64 = value;
+    CFNumberRef cfValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value64);
+    OSStatus status = VTSessionSetProperty(vtSession, key, cfValue);
+    CFRelease(cfValue);
+    return status;
+}
+
 bool VideoSampleBufferCompressor::initCompressionSession(CMVideoFormatDescriptionRef formatDescription)
 {
     CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
@@ -120,12 +134,16 @@
 
     error = VTSessionSetProperty(m_vtSession.get(), kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
     RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_RealTime failed with %d", error);
-    error = VTSessionSetProperty(m_vtSession.get(), kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, (__bridge CFTypeRef)@(m_maxKeyFrameIntervalDuration));
+    error = setCompressionSessionProperty(m_vtSession.get(), kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, m_maxKeyFrameIntervalDuration);
     RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration failed with %d", error);
-    error = VTSessionSetProperty(m_vtSession.get(), kVTCompressionPropertyKey_ExpectedFrameRate, (__bridge CFTypeRef)@(m_expectedFrameRate));
+    error = setCompressionSessionProperty(m_vtSession.get(), kVTCompressionPropertyKey_ExpectedFrameRate, m_expectedFrameRate);
     RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_ExpectedFrameRate failed with %d", error);
 
-    // FIXME: Set video compression rate.
+    if (m_outputBitRate) {
+        error = setCompressionSessionProperty(m_vtSession.get(), kVTCompressionPropertyKey_AverageBitRate, *m_outputBitRate);
+        RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_AverageBitRate failed with %d", error);
+    }
+
     error = VTCompressionSessionPrepareToEncodeFrames(m_vtSession.get());
     RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTCompressionSessionPrepareToEncodeFrames failed with %d", error);
 

Modified: trunk/Source/WebCore/testing/Internals.cpp (265327 => 265328)


--- trunk/Source/WebCore/testing/Internals.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebCore/testing/Internals.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1691,9 +1691,9 @@
         page->settings().setMediaCaptureRequiresSecureConnection(enabled);
 }
 
-static std::unique_ptr<MediaRecorderPrivate> createRecorderMockSource(MediaStreamPrivate& stream)
+static ExceptionOr<std::unique_ptr<MediaRecorderPrivate>> createRecorderMockSource(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions&)
 {
-    return std::unique_ptr<MediaRecorderPrivateMock>(new MediaRecorderPrivateMock(stream));
+    return std::unique_ptr<MediaRecorderPrivate>(new MediaRecorderPrivateMock(stream));
 }
 
 void Internals::setCustomPrivateRecorderCreator()
@@ -1700,9 +1700,8 @@
 {
     WebCore::MediaRecorder::setCustomPrivateRecorderCreator(createRecorderMockSource);
 }
+#endif // ENABLE(MEDIA_STREAM)
 
-#endif
-
 ExceptionOr<Ref<DOMRect>> Internals::absoluteCaretBounds()
 {
     Document* document = contextDocument();

Modified: trunk/Source/WebKit/ChangeLog (265327 => 265328)


--- trunk/Source/WebKit/ChangeLog	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/ChangeLog	2020-08-06 15:25:39 UTC (rev 265328)
@@ -1,3 +1,27 @@
+2020-08-06  Youenn Fablet  <you...@apple.com>
+
+        Add support for MediaRecorder bitrate options
+        https://bugs.webkit.org/show_bug.cgi?id=214973
+
+        Reviewed by Eric Carlson.
+
+        Serialize options when creating remote media recorder.
+
+        * GPUProcess/webrtc/RemoteMediaRecorder.cpp:
+        (WebKit::RemoteMediaRecorder::create):
+        * GPUProcess/webrtc/RemoteMediaRecorder.h:
+        * GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
+        (WebKit::RemoteMediaRecorderManager::createRecorder):
+        * GPUProcess/webrtc/RemoteMediaRecorderManager.h:
+        * GPUProcess/webrtc/RemoteMediaRecorderManager.messages.in:
+        * WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp:
+        (WebKit::MediaRecorderPrivate::MediaRecorderPrivate):
+        (WebKit::MediaRecorderPrivate::startRecording):
+        * WebProcess/GPU/webrtc/MediaRecorderPrivate.h:
+        * WebProcess/GPU/webrtc/MediaRecorderProvider.cpp:
+        (WebKit::MediaRecorderProvider::createMediaRecorderPrivate):
+        * WebProcess/GPU/webrtc/MediaRecorderProvider.h:
+
 2020-08-06  Adrian Perez de Castro  <ape...@igalia.com>
 
         [WPE][GTK] Wrong argument order for clone syscall seccomp filter on s390x

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.cpp (265327 => 265328)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -38,9 +38,9 @@
 namespace WebKit {
 using namespace WebCore;
 
-std::unique_ptr<RemoteMediaRecorder> RemoteMediaRecorder::create(GPUConnectionToWebProcess& gpuConnectionToWebProcess, MediaRecorderIdentifier identifier, bool recordAudio, bool recordVideo)
+std::unique_ptr<RemoteMediaRecorder> RemoteMediaRecorder::create(GPUConnectionToWebProcess& gpuConnectionToWebProcess, MediaRecorderIdentifier identifier, bool recordAudio, bool recordVideo, const MediaRecorderPrivateOptions& options)
 {
-    auto writer = MediaRecorderPrivateWriter::create(recordAudio, recordVideo);
+    auto writer = MediaRecorderPrivateWriter::create(recordAudio, recordVideo, options);
     if (!writer)
         return nullptr;
     return std::unique_ptr<RemoteMediaRecorder>(new RemoteMediaRecorder { gpuConnectionToWebProcess, identifier, writer.releaseNonNull(), recordAudio });

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.h (265327 => 265328)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorder.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -44,6 +44,7 @@
 class CARingBuffer;
 class ImageTransferSessionVT;
 class RemoteVideoSample;
+struct MediaRecorderPrivateOptions;
 }
 
 namespace WebKit {
@@ -54,7 +55,7 @@
 class RemoteMediaRecorder : private IPC::MessageReceiver {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static std::unique_ptr<RemoteMediaRecorder> create(GPUConnectionToWebProcess&, MediaRecorderIdentifier, bool recordAudio, bool recordVideo);
+    static std::unique_ptr<RemoteMediaRecorder> create(GPUConnectionToWebProcess&, MediaRecorderIdentifier, bool recordAudio, bool recordVideo, const WebCore::MediaRecorderPrivateOptions&);
     ~RemoteMediaRecorder();
 
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp (265327 => 265328)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -51,10 +51,10 @@
         recorder->didReceiveMessage(connection, decoder);
 }
 
-void RemoteMediaRecorderManager::createRecorder(MediaRecorderIdentifier identifier, bool recordAudio, bool recordVideo, CompletionHandler<void(Optional<ExceptionData>&&)>&& completionHandler)
+void RemoteMediaRecorderManager::createRecorder(MediaRecorderIdentifier identifier, bool recordAudio, bool recordVideo, const MediaRecorderPrivateOptions& options, CompletionHandler<void(Optional<ExceptionData>&&)>&& completionHandler)
 {
     ASSERT(!m_recorders.contains(identifier));
-    auto recorder = RemoteMediaRecorder::create(m_gpuConnectionToWebProcess, identifier, recordAudio, recordVideo);
+    auto recorder = RemoteMediaRecorder::create(m_gpuConnectionToWebProcess, identifier, recordAudio, recordVideo, options);
     if (!recorder)
         return completionHandler(ExceptionData { NotSupportedError, "Unable to create a recorder with the provided stream"_s });
 

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h (265327 => 265328)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -41,6 +41,7 @@
 
 namespace WebCore {
 struct ExceptionData;
+struct MediaRecorderPrivateOptions;
 }
 
 namespace WebKit {
@@ -60,7 +61,7 @@
 private:
     // IPC::MessageReceiver
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
-    void createRecorder(MediaRecorderIdentifier, bool recordAudio, bool recordVideo, CompletionHandler<void(Optional<WebCore::ExceptionData>&&)>&&);
+    void createRecorder(MediaRecorderIdentifier, bool recordAudio, bool recordVideo, const WebCore::MediaRecorderPrivateOptions&, CompletionHandler<void(Optional<WebCore::ExceptionData>&&)>&&);
     void releaseRecorder(MediaRecorderIdentifier);
 
     GPUConnectionToWebProcess& m_gpuConnectionToWebProcess;

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.messages.in (265327 => 265328)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.messages.in	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.messages.in	2020-08-06 15:25:39 UTC (rev 265328)
@@ -24,7 +24,7 @@
 #if PLATFORM(COCOA) && ENABLE(GPU_PROCESS) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
 
 messages -> RemoteMediaRecorderManager NotRefCounted {
-    CreateRecorder(WebKit::MediaRecorderIdentifier id, bool hasAudio, bool hasVideo) -> (Optional<WebCore::ExceptionData> creationError) Async
+    CreateRecorder(WebKit::MediaRecorderIdentifier id, bool hasAudio, bool hasVideo, struct WebCore::MediaRecorderPrivateOptions options) -> (Optional<WebCore::ExceptionData> creationError) Async
     ReleaseRecorder(WebKit::MediaRecorderIdentifier id)
 }
 

Modified: trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp (265327 => 265328)


--- trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -43,10 +43,11 @@
 namespace WebKit {
 using namespace WebCore;
 
-MediaRecorderPrivate::MediaRecorderPrivate(MediaStreamPrivate& stream)
+MediaRecorderPrivate::MediaRecorderPrivate(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions& options)
     : m_identifier(MediaRecorderIdentifier::generate())
     , m_stream(makeRef(stream))
     , m_connection(WebProcess::singleton().ensureGPUProcessConnection().connection())
+    , m_options(options)
 {
 }
 
@@ -59,7 +60,7 @@
     if (selectedTracks.audioTrack)
         m_ringBuffer = makeUnique<CARingBuffer>(makeUniqueRef<SharedRingBufferStorage>(this));
 
-    m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorderManager::CreateRecorder { m_identifier, !!selectedTracks.audioTrack, !!selectedTracks.videoTrack }, [this, weakThis = makeWeakPtr(this), audioTrack = makeRefPtr(selectedTracks.audioTrack), videoTrack = makeRefPtr(selectedTracks.videoTrack), errorCallback = WTFMove(errorCallback)](auto&& exception) mutable {
+    m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorderManager::CreateRecorder { m_identifier, !!selectedTracks.audioTrack, !!selectedTracks.videoTrack, m_options }, [this, weakThis = makeWeakPtr(this), audioTrack = makeRefPtr(selectedTracks.audioTrack), videoTrack = makeRefPtr(selectedTracks.videoTrack), errorCallback = WTFMove(errorCallback)](auto&& exception) mutable {
         if (!weakThis) {
             errorCallback({ });
             return;

Modified: trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.h (265327 => 265328)


--- trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -50,7 +50,7 @@
     , public CanMakeWeakPtr<MediaRecorderPrivate> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    explicit MediaRecorderPrivate(WebCore::MediaStreamPrivate&);
+    MediaRecorderPrivate(WebCore::MediaStreamPrivate&, const WebCore::MediaRecorderPrivateOptions&);
     ~MediaRecorderPrivate();
 
 private:
@@ -71,6 +71,7 @@
     std::unique_ptr<WebCore::CARingBuffer> m_ringBuffer;
     WebCore::CAAudioStreamDescription m_description { };
     int64_t m_numberOfFrames { 0 };
+    WebCore::MediaRecorderPrivateOptions m_options;
 };
 
 }

Modified: trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.cpp (265327 => 265328)


--- trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.cpp	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.cpp	2020-08-06 15:25:39 UTC (rev 265328)
@@ -34,13 +34,13 @@
 namespace WebKit {
 using namespace WebCore;
 
-std::unique_ptr<WebCore::MediaRecorderPrivate> MediaRecorderProvider::createMediaRecorderPrivate(MediaStreamPrivate& stream)
+std::unique_ptr<WebCore::MediaRecorderPrivate> MediaRecorderProvider::createMediaRecorderPrivate(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions& options)
 {
 #if ENABLE(GPU_PROCESS) && HAVE(AVASSETWRITERDELEGATE)
     if (m_useGPUProcess)
-        return makeUnique<MediaRecorderPrivate>(stream);
+        return makeUnique<MediaRecorderPrivate>(stream, options);
 #endif
-    return WebCore::MediaRecorderProvider::createMediaRecorderPrivate(stream);
+    return WebCore::MediaRecorderProvider::createMediaRecorderPrivate(stream, options);
 }
 
 }

Modified: trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.h (265327 => 265328)


--- trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.h	2020-08-06 14:55:55 UTC (rev 265327)
+++ trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderProvider.h	2020-08-06 15:25:39 UTC (rev 265328)
@@ -35,7 +35,7 @@
 
 private:
 #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
-    std::unique_ptr<WebCore::MediaRecorderPrivate> createMediaRecorderPrivate(WebCore::MediaStreamPrivate&) final;
+    std::unique_ptr<WebCore::MediaRecorderPrivate> createMediaRecorderPrivate(WebCore::MediaStreamPrivate&, const WebCore::MediaRecorderPrivateOptions&) final;
 #endif
 };
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to