Title: [268106] branches/safari-610-branch
Revision
268106
Author
[email protected]
Date
2020-10-06 18:02:59 -0700 (Tue, 06 Oct 2020)

Log Message

Cherry-pick r267987. rdar://problem/70025699

    MediaRecorder should respect enabled and muted tracks
    https://bugs.webkit.org/show_bug.cgi?id=217312

    Reviewed by Eric Carlson.

    Source/WebCore:

    If track is muted, replace it by either silence (audio buffer filled with zeros) or black frames.
    MediaRecorderPrivate will keep track of whether the selected track should be muted.
    It is then the responsibility of the specialization to do the appropriate processing.

    Test: http/wpt/mediarecorder/mute-tracks.html

    * Modules/mediarecorder/MediaRecorder.cpp:
    (WebCore::MediaRecorder::trackMutedChanged):
    (WebCore::MediaRecorder::trackEnabledChanged):
    * Modules/mediarecorder/MediaRecorder.h:
    * platform/audio/cocoa/WebAudioBufferList.cpp:
    (WebCore::WebAudioBufferList::zeroFlatBuffer):
    * platform/audio/cocoa/WebAudioBufferList.h:
    * platform/mediarecorder/MediaRecorderPrivate.cpp:
    (WebCore::MediaRecorderPrivate::selectTracks):
    (WebCore::MediaRecorderPrivate::checkTrackState):
    * platform/mediarecorder/MediaRecorderPrivate.h:
    (WebCore::MediaRecorderPrivate::trackMutedChanged):
    (WebCore::MediaRecorderPrivate::trackEnabledChanged):
    (WebCore::MediaRecorderPrivate::shouldMuteAudio const):
    (WebCore::MediaRecorderPrivate::shouldMuteVideo const):
    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
    (WebCore::MediaRecorderPrivateAVFImpl::create):
    (WebCore::MediaRecorderPrivateAVFImpl::videoSampleAvailable):
    (WebCore::MediaRecorderPrivateAVFImpl::audioSamplesAvailable):
    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:

    LayoutTests:

    * http/wpt/mediarecorder/mute-tracks-expected.txt: Added.
    * http/wpt/mediarecorder/mute-tracks.html: Added.

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267987 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Added Paths

Diff

Modified: branches/safari-610-branch/LayoutTests/ChangeLog (268105 => 268106)


--- branches/safari-610-branch/LayoutTests/ChangeLog	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/LayoutTests/ChangeLog	2020-10-07 01:02:59 UTC (rev 268106)
@@ -1,5 +1,61 @@
 2020-10-06  Alan Coon  <[email protected]>
 
+        Cherry-pick r267987. rdar://problem/70025699
+
+    MediaRecorder should respect enabled and muted tracks
+    https://bugs.webkit.org/show_bug.cgi?id=217312
+    
+    Reviewed by Eric Carlson.
+    
+    Source/WebCore:
+    
+    If track is muted, replace it by either silence (audio buffer filled with zeros) or black frames.
+    MediaRecorderPrivate will keep track of whether the selected track should be muted.
+    It is then the responsibility of the specialization to do the appropriate processing.
+    
+    Test: http/wpt/mediarecorder/mute-tracks.html
+    
+    * Modules/mediarecorder/MediaRecorder.cpp:
+    (WebCore::MediaRecorder::trackMutedChanged):
+    (WebCore::MediaRecorder::trackEnabledChanged):
+    * Modules/mediarecorder/MediaRecorder.h:
+    * platform/audio/cocoa/WebAudioBufferList.cpp:
+    (WebCore::WebAudioBufferList::zeroFlatBuffer):
+    * platform/audio/cocoa/WebAudioBufferList.h:
+    * platform/mediarecorder/MediaRecorderPrivate.cpp:
+    (WebCore::MediaRecorderPrivate::selectTracks):
+    (WebCore::MediaRecorderPrivate::checkTrackState):
+    * platform/mediarecorder/MediaRecorderPrivate.h:
+    (WebCore::MediaRecorderPrivate::trackMutedChanged):
+    (WebCore::MediaRecorderPrivate::trackEnabledChanged):
+    (WebCore::MediaRecorderPrivate::shouldMuteAudio const):
+    (WebCore::MediaRecorderPrivate::shouldMuteVideo const):
+    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
+    (WebCore::MediaRecorderPrivateAVFImpl::create):
+    (WebCore::MediaRecorderPrivateAVFImpl::videoSampleAvailable):
+    (WebCore::MediaRecorderPrivateAVFImpl::audioSamplesAvailable):
+    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:
+    
+    LayoutTests:
+    
+    * http/wpt/mediarecorder/mute-tracks-expected.txt: Added.
+    * http/wpt/mediarecorder/mute-tracks.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267987 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-10-05  Youenn Fablet  <[email protected]>
+
+            MediaRecorder should respect enabled and muted tracks
+            https://bugs.webkit.org/show_bug.cgi?id=217312
+
+            Reviewed by Eric Carlson.
+
+            * http/wpt/mediarecorder/mute-tracks-expected.txt: Added.
+            * http/wpt/mediarecorder/mute-tracks.html: Added.
+
+2020-10-06  Alan Coon  <[email protected]>
+
         Cherry-pick r267870. rdar://problem/70025703
 
     Add AVAssetWriter SPI header

Added: branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks-expected.txt (0 => 268106)


--- branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks-expected.txt	                        (rev 0)
+++ branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks-expected.txt	2020-10-07 01:02:59 UTC (rev 268106)
@@ -0,0 +1,6 @@
+
+
+PASS Recording a muted audio track should prodcue silence
+PASS Muting an audio track should record silence
+PASS Muting a video track should produce black frames
+

Added: branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks.html (0 => 268106)


--- branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks.html	                        (rev 0)
+++ branches/safari-610-branch/LayoutTests/http/wpt/mediarecorder/mute-tracks.html	2020-10-07 01:02:59 UTC (rev 268106)
@@ -0,0 +1,211 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>A recorded muted audio track should produce silence</title>
+    <script src=""
+    <script src=""
+</head>
+<body>
+    <video id="video1" controls></video>
+    <video id="video2" controls></video>
+    <video id="video3" controls></video>
+    <canvas id="canvas3" width="320" height="240"></canvas>
+    <script>
+if (window.internals)
+    window.internals.setUseGPUProcessForWebRTC(false);
+
+function analyseAudio(streamOrVideo, duration, context)
+{
+    return new Promise((resolve, reject) => {
+        var sourceNode = streamOrVideo instanceof MediaStream ? context.createMediaStreamSource(streamOrVideo) : context.createMediaElementSource(streamOrVideo);
+
+        var analyser = context.createAnalyser();
+        var gain = context.createGain();
+
+        var results = { heardHum: false, heardBip: false, heardBop: false, heardNoise: false };
+
+        analyser.fftSize = 2048;
+        analyser.smoothingTimeConstant = 0;
+        analyser.minDecibels = -100;
+        analyser.maxDecibels = 0;
+        gain.gain.value = 0;
+
+        sourceNode.connect(analyser);
+        analyser.connect(gain);
+        gain.connect(context.destination);
+
+       function analyse() {
+           var freqDomain = new Uint8Array(analyser.frequencyBinCount);
+           analyser.getByteFrequencyData(freqDomain);
+
+           var hasFrequency = expectedFrequency => {
+                var bin = Math.floor(expectedFrequency * analyser.fftSize / context.sampleRate);
+                return bin < freqDomain.length && freqDomain[bin] >= 150;
+           };
+
+           if (!results.heardHum)
+                results.heardHum = hasFrequency(150);
+
+           if (!results.heardBip)
+               results.heardBip = hasFrequency(1500);
+
+           if (!results.heardBop)
+                results.heardBop = hasFrequency(500);
+
+           if (!results.heardNoise)
+                results.heardNoise = hasFrequency(3000);
+
+           if (results.heardHum && results.heardBip && results.heardBop && results.heardNoise)
+                done();
+        };
+
+       function done() {
+            clearTimeout(timeout);
+            clearInterval(interval);
+
+            resolve(results);
+       }
+
+        var timeout = setTimeout(done, 3 * duration);
+        var interval = setInterval(analyse, duration / 30);
+        analyse();
+    });
+}
+
+function waitFor(duration)
+{
+    return new Promise((resolve) => setTimeout(resolve, duration));
+}
+
+async function doHumAnalysis(streamOrVideo, expected)
+{
+    var context = new AudioContext();
+    for (var cptr = 0; cptr < 20; cptr++) {
+        var results = await analyseAudio(streamOrVideo, 200, context);
+        if (results.heardHum === expected)
+            return true;
+        await waitFor(50);
+    }
+    await context.close();
+    return false;
+}
+
+function isVideoBlack(canvas, video, startX, startY, grabbedWidth, grabbedHeight)
+{
+    canvas.width = video.videoWidth;
+    canvas.height = video.videoHeight;
+    if (!grabbedHeight) {
+        startX = 10;
+        startY = 10;
+        grabbedWidth = canvas.width - 20;
+        grabbedHeight = canvas.height - 20;
+    }
+
+    canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
+
+    imageData = canvas.getContext('2d').getImageData(startX, startY, grabbedWidth, grabbedHeight);
+    data = ""
+    for (var cptr = 0; cptr < grabbedWidth * grabbedHeight; ++cptr) {
+        // Approximatively black pixels.
+        if (data[4 * cptr] > 30 || data[4 * cptr + 1] > 30 || data[4 * cptr + 2] > 30)
+            return false;
+    }
+    return true;
+}
+
+async function checkVideoBlack(expected, canvas, video, errorMessage, counter)
+{
+    if (isVideoBlack(canvas, video) === expected)
+        return Promise.resolve();
+
+    if (counter === undefined)
+        counter = 0;
+    if (counter > 400) {
+        if (!errorMessage)
+            errorMessage = "checkVideoBlack timed out expecting " + expected;
+        return Promise.reject(errorMessage);
+    }
+
+    await waitFor(50);
+    return checkVideoBlack(expected, canvas, video, errorMessage, ++counter);
+}
+
+promise_test(async (test) => {
+    const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
+
+    const localTrack = stream.getAudioTracks()[0];
+    localTrack.enabled = false;
+    setTimeout(() => localTrack.enabled = false, 0);
+    const recorder = new MediaRecorder(stream);
+    const dataPromise = new Promise(resolve => recorder._ondataavailable_ = (e) => resolve(e.data));
+
+    recorder.start();
+    await waitFor(1000);
+    recorder.stop();
+    const blob = await dataPromise;
+
+    const url = ""
+    video1.src = ""
+    await video1.play();
+
+    assert_greater_than(video1.duration, 0.5);
+
+    const results = await doHumAnalysis(video1, false); 
+    assert_true(results, "Should not hear hum");
+
+    URL.revokeObjectURL(url);
+}, "Recording a muted audio track should prodcue silence");
+
+promise_test(async (test) => {
+    const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
+
+    const localTrack = stream.getAudioTracks()[0];
+    setTimeout(() => localTrack.enabled = false, 50);
+    const recorder = new MediaRecorder(stream);
+    const dataPromise = new Promise(resolve => recorder._ondataavailable_ = (e) => resolve(e.data));
+
+    recorder.start();
+    await waitFor(1000);
+    recorder.stop();
+    const blob = await dataPromise;
+
+    const url = ""
+    video2.src = ""
+    await video2.play();
+
+    assert_greater_than(video2.duration, 0.5);
+
+    const results = await doHumAnalysis(video2, false); 
+    assert_true(results, "Should not hear hum");
+
+    URL.revokeObjectURL(url);
+}, "Muting an audio track should record silence");
+
+promise_test(async (test) => {
+    const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
+
+    const localTrack = stream.getVideoTracks()[0];
+    setTimeout(() => localTrack.enabled = false, 50);
+    const recorder = new MediaRecorder(stream);
+    const dataPromise = new Promise(resolve => recorder._ondataavailable_ = (e) => resolve(e.data));
+
+    recorder.start();
+    await waitFor(1000);
+    recorder.stop();
+    const blob = await dataPromise;
+
+    const url = ""
+    video3.src = ""
+    await video3.play();
+
+    assert_greater_than(video3.duration, 0.5);
+
+    const result = await checkVideoBlack(true, canvas3, video3, "muted video should produce black frames");
+
+    URL.revokeObjectURL(url);
+}, "Muting a video track should produce black frames");
+
+    </script>
+</body>
+</html>

Modified: branches/safari-610-branch/Source/WebCore/ChangeLog (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/ChangeLog	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/ChangeLog	2020-10-07 01:02:59 UTC (rev 268106)
@@ -1,5 +1,85 @@
 2020-10-06  Alan Coon  <[email protected]>
 
+        Cherry-pick r267987. rdar://problem/70025699
+
+    MediaRecorder should respect enabled and muted tracks
+    https://bugs.webkit.org/show_bug.cgi?id=217312
+    
+    Reviewed by Eric Carlson.
+    
+    Source/WebCore:
+    
+    If track is muted, replace it by either silence (audio buffer filled with zeros) or black frames.
+    MediaRecorderPrivate will keep track of whether the selected track should be muted.
+    It is then the responsibility of the specialization to do the appropriate processing.
+    
+    Test: http/wpt/mediarecorder/mute-tracks.html
+    
+    * Modules/mediarecorder/MediaRecorder.cpp:
+    (WebCore::MediaRecorder::trackMutedChanged):
+    (WebCore::MediaRecorder::trackEnabledChanged):
+    * Modules/mediarecorder/MediaRecorder.h:
+    * platform/audio/cocoa/WebAudioBufferList.cpp:
+    (WebCore::WebAudioBufferList::zeroFlatBuffer):
+    * platform/audio/cocoa/WebAudioBufferList.h:
+    * platform/mediarecorder/MediaRecorderPrivate.cpp:
+    (WebCore::MediaRecorderPrivate::selectTracks):
+    (WebCore::MediaRecorderPrivate::checkTrackState):
+    * platform/mediarecorder/MediaRecorderPrivate.h:
+    (WebCore::MediaRecorderPrivate::trackMutedChanged):
+    (WebCore::MediaRecorderPrivate::trackEnabledChanged):
+    (WebCore::MediaRecorderPrivate::shouldMuteAudio const):
+    (WebCore::MediaRecorderPrivate::shouldMuteVideo const):
+    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
+    (WebCore::MediaRecorderPrivateAVFImpl::create):
+    (WebCore::MediaRecorderPrivateAVFImpl::videoSampleAvailable):
+    (WebCore::MediaRecorderPrivateAVFImpl::audioSamplesAvailable):
+    * platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:
+    
+    LayoutTests:
+    
+    * http/wpt/mediarecorder/mute-tracks-expected.txt: Added.
+    * http/wpt/mediarecorder/mute-tracks.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267987 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2020-10-05  Youenn Fablet  <[email protected]>
+
+            MediaRecorder should respect enabled and muted tracks
+            https://bugs.webkit.org/show_bug.cgi?id=217312
+
+            Reviewed by Eric Carlson.
+
+            If track is muted, replace it by either silence (audio buffer filled with zeros) or black frames.
+            MediaRecorderPrivate will keep track of whether the selected track should be muted.
+            It is then the responsibility of the specialization to do the appropriate processing.
+
+            Test: http/wpt/mediarecorder/mute-tracks.html
+
+            * Modules/mediarecorder/MediaRecorder.cpp:
+            (WebCore::MediaRecorder::trackMutedChanged):
+            (WebCore::MediaRecorder::trackEnabledChanged):
+            * Modules/mediarecorder/MediaRecorder.h:
+            * platform/audio/cocoa/WebAudioBufferList.cpp:
+            (WebCore::WebAudioBufferList::zeroFlatBuffer):
+            * platform/audio/cocoa/WebAudioBufferList.h:
+            * platform/mediarecorder/MediaRecorderPrivate.cpp:
+            (WebCore::MediaRecorderPrivate::selectTracks):
+            (WebCore::MediaRecorderPrivate::checkTrackState):
+            * platform/mediarecorder/MediaRecorderPrivate.h:
+            (WebCore::MediaRecorderPrivate::trackMutedChanged):
+            (WebCore::MediaRecorderPrivate::trackEnabledChanged):
+            (WebCore::MediaRecorderPrivate::shouldMuteAudio const):
+            (WebCore::MediaRecorderPrivate::shouldMuteVideo const):
+            * platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp:
+            (WebCore::MediaRecorderPrivateAVFImpl::create):
+            (WebCore::MediaRecorderPrivateAVFImpl::videoSampleAvailable):
+            (WebCore::MediaRecorderPrivateAVFImpl::audioSamplesAvailable):
+            * platform/mediarecorder/MediaRecorderPrivateAVFImpl.h:
+
+2020-10-06  Alan Coon  <[email protected]>
+
         Cherry-pick r267870. rdar://problem/70025703
 
     Add AVAssetWriter SPI header

Modified: branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp	2020-10-07 01:02:59 UTC (rev 268106)
@@ -300,6 +300,18 @@
     stopRecording();
 }
 
+void MediaRecorder::trackMutedChanged(MediaStreamTrackPrivate& track)
+{
+    if (m_private)
+        m_private->trackMutedChanged(track);
+}
+
+void MediaRecorder::trackEnabledChanged(MediaStreamTrackPrivate& track)
+{
+    if (m_private)
+        m_private->trackEnabledChanged(track);
+}
+
 bool MediaRecorder::virtualHasPendingActivity() const
 {
     return m_state != RecordingState::Inactive;

Modified: branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.h (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.h	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/Modules/mediarecorder/MediaRecorder.h	2020-10-07 01:02:59 UTC (rev 268106)
@@ -108,9 +108,9 @@
 
     // MediaStreamTrackPrivate::Observer
     void trackEnded(MediaStreamTrackPrivate&) final;
-    void trackMutedChanged(MediaStreamTrackPrivate&) final { };
+    void trackMutedChanged(MediaStreamTrackPrivate&) final;
+    void trackEnabledChanged(MediaStreamTrackPrivate&) final;
     void trackSettingsChanged(MediaStreamTrackPrivate&) final { };
-    void trackEnabledChanged(MediaStreamTrackPrivate&) final { };
 
     static CreatorFunction m_customCreator;
 

Modified: branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.cpp (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.cpp	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.cpp	2020-10-07 01:02:59 UTC (rev 268106)
@@ -146,4 +146,9 @@
     return nullptr;
 }
 
+void WebAudioBufferList::zeroFlatBuffer()
+{
+    memset(m_flatBuffer.data(), 0, m_flatBuffer.capacity());
 }
+
+}

Modified: branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.h (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.h	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/audio/cocoa/WebAudioBufferList.h	2020-10-07 01:02:59 UTC (rev 268106)
@@ -58,6 +58,8 @@
 
     WEBCORE_EXPORT static bool isSupportedDescription(const CAAudioStreamDescription&, uint32_t sampleCount);
 
+    void zeroFlatBuffer();
+
 private:
     Kind kind() const { return Kind::WebAudioBufferList; }
 

Modified: branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.cpp (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.cpp	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.cpp	2020-10-07 01:02:59 UTC (rev 268106)
@@ -36,7 +36,7 @@
 {
     AudioVideoSelectedTracks selectedTracks;
     stream.forEachTrack([&](auto& track) {
-        if (!track.enabled() || track.ended())
+        if (track.ended())
             return;
         switch (track.type()) {
         case RealtimeMediaSource::Type::Video: {
@@ -56,6 +56,16 @@
     return selectedTracks;
 }
 
+void MediaRecorderPrivate::checkTrackState(const MediaStreamTrackPrivate& track)
+{
+    if (&track.source() == m_audioSource.get()) {
+        m_shouldMuteAudio = track.muted() || !track.enabled();
+        return;
+    }
+    if (&track.source() == m_videoSource.get())
+        m_shouldMuteVideo = track.muted() || !track.enabled();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)

Modified: branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h	2020-10-07 01:02:59 UTC (rev 268106)
@@ -65,11 +65,21 @@
     using StartRecordingCallback = CompletionHandler<void(ExceptionOr<String>&&)>;
     virtual void startRecording(StartRecordingCallback&& callback) { callback(String(mimeType())); }
 
+    void trackMutedChanged(MediaStreamTrackPrivate& track) { checkTrackState(track); }
+    void trackEnabledChanged(MediaStreamTrackPrivate& track) { checkTrackState(track); }
+
 protected:
     void setAudioSource(RefPtr<RealtimeMediaSource>&&);
     void setVideoSource(RefPtr<RealtimeMediaSource>&&);
 
+    void checkTrackState(const MediaStreamTrackPrivate&);
+
+    bool shouldMuteAudio() const { return m_shouldMuteAudio; }
+    bool shouldMuteVideo() const { return m_shouldMuteVideo; }
+
 private:
+    bool m_shouldMuteAudio { false };
+    bool m_shouldMuteVideo { false };
     RefPtr<RealtimeMediaSource> m_audioSource;
     RefPtr<RealtimeMediaSource> m_videoSource;
 };

Modified: branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.cpp	2020-10-07 01:02:59 UTC (rev 268106)
@@ -29,13 +29,20 @@
 #if ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
 
 #include "AudioStreamDescription.h"
+#include "CAAudioStreamDescription.h"
+#include "Logging.h"
 #include "MediaRecorderPrivateWriterCocoa.h"
-#include "MediaSample.h"
+#include "MediaSampleAVFObjC.h"
 #include "MediaStreamPrivate.h"
+#include "RealtimeIncomingVideoSourceCocoa.h"
 #include "SharedBuffer.h"
 #include "WebAudioBufferList.h"
 
+#include "CoreVideoSoftLink.h"
+#include <pal/cf/CoreMediaSoftLink.h>
+
 namespace WebCore {
+using namespace PAL;
 
 std::unique_ptr<MediaRecorderPrivateAVFImpl> MediaRecorderPrivateAVFImpl::create(MediaStreamPrivate& stream, const MediaRecorderPrivateOptions& options)
 {
@@ -50,10 +57,14 @@
         return nullptr;
 
     auto recorder = std::unique_ptr<MediaRecorderPrivateAVFImpl>(new MediaRecorderPrivateAVFImpl(writer.releaseNonNull()));
-    if (selectedTracks.audioTrack)
+    if (selectedTracks.audioTrack) {
         recorder->setAudioSource(&selectedTracks.audioTrack->source());
-    if (selectedTracks.videoTrack)
+        recorder->checkTrackState(*selectedTracks.audioTrack);
+    }
+    if (selectedTracks.videoTrack) {
         recorder->setVideoSource(&selectedTracks.videoTrack->source());
+        recorder->checkTrackState(*selectedTracks.videoTrack);
+    }
     return recorder;
 }
 
@@ -70,6 +81,37 @@
 
 void MediaRecorderPrivateAVFImpl::videoSampleAvailable(MediaSample& sampleBuffer)
 {
+    if (shouldMuteVideo()) {
+        if (!m_blackFrame) {
+            m_blackFrameDescription = CMSampleBufferGetFormatDescription(sampleBuffer.platformSample().sample.cmSampleBuffer);
+            auto dimensions = CMVideoFormatDescriptionGetDimensions(m_blackFrameDescription.get());
+            m_blackFrame = createBlackPixelBuffer(dimensions.width, dimensions.height);
+
+            CMVideoFormatDescriptionRef formatDescription = nullptr;
+            auto status = CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, m_blackFrame.get(), &formatDescription);
+            if (status != noErr) {
+                RELEASE_LOG_ERROR(Media, "MediaRecorderPrivateAVFImpl::videoSampleAvailable ::unable to create a black frame description: %d", static_cast<int>(status));
+                m_blackFrame = nullptr;
+                return;
+            }
+            m_blackFrameDescription = adoptCF(formatDescription);
+        }
+
+        CMSampleBufferRef sample = nullptr;
+        CMSampleTimingInfo timingInfo { kCMTimeInvalid, toCMTime(sampleBuffer.presentationTime()), toCMTime(sampleBuffer.decodeTime()) };
+        auto status = CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault, (CVImageBufferRef)m_blackFrame.get(), m_blackFrameDescription.get(), &timingInfo, &sample);
+
+        if (status != noErr) {
+            RELEASE_LOG_ERROR(MediaStream, "MediaRecorderPrivateAVFImpl::videoSampleAvailable - unable to create a black frame: %d", static_cast<int>(status));
+            return;
+        }
+        auto newSample = adoptCF(sample);
+        m_writer->appendVideoSampleBuffer(MediaSampleAVFObjC::create(newSample.get(), sampleBuffer.videoRotation(), sampleBuffer.videoMirrored()));
+        return;
+    }
+
+    m_blackFrame = nullptr;
+    m_blackFrameDescription = nullptr;
     m_writer->appendVideoSampleBuffer(sampleBuffer);
 }
 
@@ -77,6 +119,18 @@
 {
     ASSERT(is<WebAudioBufferList>(data));
     ASSERT(description.platformDescription().type == PlatformDescription::CAAudioStreamBasicType);
+
+    if (shouldMuteAudio()) {
+        if (!m_audioBuffer || m_description != toCAAudioStreamDescription(description)) {
+            m_description = toCAAudioStreamDescription(description);
+            m_audioBuffer = makeUnique<WebAudioBufferList>(m_description, sampleCount);
+        } else
+            m_audioBuffer->setSampleCount(sampleCount);
+        m_audioBuffer->zeroFlatBuffer();
+        m_writer->appendAudioSampleBuffer(*m_audioBuffer, description, mediaTime, sampleCount);
+        return;
+    }
+
     m_writer->appendAudioSampleBuffer(data, description, mediaTime, sampleCount);
 }
 

Modified: branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h (268105 => 268106)


--- branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h	2020-10-07 01:02:55 UTC (rev 268105)
+++ branches/safari-610-branch/Source/WebCore/platform/mediarecorder/MediaRecorderPrivateAVFImpl.h	2020-10-07 01:02:59 UTC (rev 268106)
@@ -26,12 +26,17 @@
 
 #if ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
 
+#include "CAAudioStreamDescription.h"
 #include "MediaRecorderPrivate.h"
 #include "MediaRecorderPrivateWriterCocoa.h"
 
+using CVPixelBufferRef = struct __CVBuffer*;
+typedef const struct opaqueCMFormatDescription* CMFormatDescriptionRef;
+
 namespace WebCore {
 
 class MediaStreamPrivate;
+class WebAudioBufferList;
 
 class MediaRecorderPrivateAVFImpl final
     : public MediaRecorderPrivate {
@@ -53,6 +58,10 @@
     void stopRecording();
 
     Ref<MediaRecorderPrivateWriter> m_writer;
+    RetainPtr<CVPixelBufferRef> m_blackFrame;
+    RetainPtr<CMFormatDescriptionRef> m_blackFrameDescription;
+    CAAudioStreamDescription m_description;
+    std::unique_ptr<WebAudioBufferList> m_audioBuffer;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to