Changeset 263511 in webkit


Ignore:
Timestamp:
Jun 25, 2020 8:58:41 AM (4 years ago)
Author:
youenn@apple.com
Message:

MediaRecorder stopRecorder() returns empty Blob after first use
https://bugs.webkit.org/show_bug.cgi?id=212274
<rdar://problem/63601298>

Reviewed by Eric Carlson.

Source/WebCore:

Refactor code to create/destroy MediaRecorderPrivate on MediaRecorder start/stop.
This allows reusing a MediaRecorder after a stop and restarting with a clean state.

We introduce MediaRecorderPrivate::startRecording to do the initialization,
which allows to fix a potential ref cycle as part of the error callback handling.

Make some improvements to the platform implementation, in particular add default initialization to all fields.
Align the code using AudioConverterRef to what is done in AudioSampleDataSource.
Also call VTCompressionSessionInvalidate when destroying the VideoSampleBufferCompressor.

Test: http/wpt/mediarecorder/MediaRecorder-multiple-start-stop.html

  • Modules/mediarecorder/MediaRecorder.cpp:

(WebCore::MediaRecorder::create):
(WebCore::MediaRecorder::MediaRecorder):
(WebCore::MediaRecorder::startRecording):
(WebCore::MediaRecorder::stopRecording):
(WebCore::MediaRecorder::requestData):

  • Modules/mediarecorder/MediaRecorder.h:
  • platform/mediarecorder/MediaRecorderPrivate.h:

(WebCore::MediaRecorderPrivate::startRecording):

  • platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h:
  • platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm:

(WebCore::AudioSampleBufferCompressor::~AudioSampleBufferCompressor):
(WebCore::AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription):
(WebCore::AudioSampleBufferCompressor::attachPrimingTrimsIfNeeded):
(WebCore::AudioSampleBufferCompressor::gradualDecoderRefreshCount):
(WebCore::AudioSampleBufferCompressor::sampleBufferWithNumPackets):
(WebCore::AudioSampleBufferCompressor::processSampleBuffersUntilLowWaterTime):

  • platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
  • platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:

(WebCore::MediaRecorderPrivateWriter::stopRecording):

  • platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:

(WebCore::VideoSampleBufferCompressor::~VideoSampleBufferCompressor):

Source/WebKit:

Update implementation to do initialization as part of startRecording.

  • GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:

(WebKit::RemoteMediaRecorderManager::releaseRecorder):
Remove ASSERT as recorder creation in WebProcess is always ok while creation in GPUProcess may fail and m_recorders may not be populated.

  • WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp:

(WebKit::MediaRecorderPrivate::MediaRecorderPrivate):
(WebKit::MediaRecorderPrivate::startRecording):

  • WebProcess/GPU/webrtc/MediaRecorderPrivate.h:

LayoutTests:

  • http/wpt/mediarecorder/MediaRecorder-multiple-start-stop-expected.txt: Added.
  • http/wpt/mediarecorder/MediaRecorder-multiple-start-stop.html: Added.
Location:
trunk
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r263510 r263511  
     12020-06-25  Youenn Fablet  <youenn@apple.com>
     2
     3        MediaRecorder stopRecorder() returns empty Blob after first use
     4        https://bugs.webkit.org/show_bug.cgi?id=212274
     5        <rdar://problem/63601298>
     6
     7        Reviewed by Eric Carlson.
     8
     9        * http/wpt/mediarecorder/MediaRecorder-multiple-start-stop-expected.txt: Added.
     10        * http/wpt/mediarecorder/MediaRecorder-multiple-start-stop.html: Added.
     11
    1122020-06-25  Karl Rackler  <rackler@apple.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r263509 r263511  
     12020-06-25  Youenn Fablet  <youenn@apple.com>
     2
     3        MediaRecorder stopRecorder() returns empty Blob after first use
     4        https://bugs.webkit.org/show_bug.cgi?id=212274
     5        <rdar://problem/63601298>
     6
     7        Reviewed by Eric Carlson.
     8
     9        Refactor code to create/destroy MediaRecorderPrivate on MediaRecorder start/stop.
     10        This allows reusing a MediaRecorder after a stop and restarting with a clean state.
     11
     12        We introduce MediaRecorderPrivate::startRecording to do the initialization,
     13        which allows to fix a potential ref cycle as part of the error callback handling.
     14
     15        Make some improvements to the platform implementation, in particular add default initialization to all fields.
     16        Align the code using AudioConverterRef to what is done in AudioSampleDataSource.
     17        Also call VTCompressionSessionInvalidate when destroying the VideoSampleBufferCompressor.
     18
     19        Test: http/wpt/mediarecorder/MediaRecorder-multiple-start-stop.html
     20
     21        * Modules/mediarecorder/MediaRecorder.cpp:
     22        (WebCore::MediaRecorder::create):
     23        (WebCore::MediaRecorder::MediaRecorder):
     24        (WebCore::MediaRecorder::startRecording):
     25        (WebCore::MediaRecorder::stopRecording):
     26        (WebCore::MediaRecorder::requestData):
     27        * Modules/mediarecorder/MediaRecorder.h:
     28        * platform/mediarecorder/MediaRecorderPrivate.h:
     29        (WebCore::MediaRecorderPrivate::startRecording):
     30        * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h:
     31        * platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm:
     32        (WebCore::AudioSampleBufferCompressor::~AudioSampleBufferCompressor):
     33        (WebCore::AudioSampleBufferCompressor::initAudioConverterForSourceFormatDescription):
     34        (WebCore::AudioSampleBufferCompressor::attachPrimingTrimsIfNeeded):
     35        (WebCore::AudioSampleBufferCompressor::gradualDecoderRefreshCount):
     36        (WebCore::AudioSampleBufferCompressor::sampleBufferWithNumPackets):
     37        (WebCore::AudioSampleBufferCompressor::processSampleBuffersUntilLowWaterTime):
     38        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
     39        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:
     40        (WebCore::MediaRecorderPrivateWriter::stopRecording):
     41        * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:
     42        (WebCore::VideoSampleBufferCompressor::~VideoSampleBufferCompressor):
     43
    1442020-06-25  Zalan Bujtas  <zalan@apple.com>
    245
  • trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.cpp

    r263422 r263511  
    5252    if (!privateInstance)
    5353        return Exception { NotSupportedError, "The MediaRecorder is unsupported on this platform"_s };
    54     auto recorder = adoptRef(*new MediaRecorder(document, WTFMove(stream), WTFMove(privateInstance), WTFMove(options)));
     54    auto recorder = adoptRef(*new MediaRecorder(document, WTFMove(stream), WTFMove(options)));
    5555    recorder->suspendIfNeeded();
    56     recorder->m_private->setErrorCallback([recorder](auto&& exception) mutable {
    57         recorder->dispatchError(WTFMove(*exception));
    58     });
    5956    return recorder;
    6057}
     
    8380}
    8481
    85 MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, std::unique_ptr<MediaRecorderPrivate>&& privateImpl, Options&& option)
     82MediaRecorder::MediaRecorder(Document& document, Ref<MediaStream>&& stream, Options&& option)
    8683    : ActiveDOMObject(document)
    8784    , m_options(WTFMove(option))
    8885    , m_stream(WTFMove(stream))
    89     , m_private(WTFMove(privateImpl))
    9086{
    9187    m_tracks = WTF::map(m_stream->getTracks(), [] (auto&& track) -> Ref<MediaStreamTrackPrivate> {
     
    133129{
    134130    UNUSED_PARAM(timeslice);
     131    if (!m_isActive)
     132        return Exception { InvalidStateError, "The MediaRecorder is not active"_s };
     133
    135134    if (state() != RecordingState::Inactive)
    136135        return Exception { InvalidStateError, "The MediaRecorder's state must be inactive in order to start recording"_s };
    137    
     136
     137    ASSERT(!m_private);
     138    m_private = createMediaRecorderPrivate(*document(), m_stream->privateStream());
     139
     140    if (!m_private)
     141        return Exception { NotSupportedError, "The MediaRecorder is unsupported on this platform"_s };
     142
     143    m_private->startRecording([this, pendingActivity = makePendingActivity(*this)](auto&& exception) mutable {
     144        if (!m_isActive || !exception)
     145            return;
     146
     147        stopRecordingInternal();
     148        dispatchError(WTFMove(*exception));
     149    });
     150
    138151    for (auto& track : m_tracks)
    139152        track->addObserver(*this);
     
    147160    if (state() == RecordingState::Inactive)
    148161        return Exception { InvalidStateError, "The MediaRecorder's state cannot be inactive"_s };
    149    
    150     queueTaskKeepingObjectAlive(*this, TaskSource::Networking, [this] {
    151         if (!m_isActive || state() == RecordingState::Inactive)
    152             return;
    153 
    154         stopRecordingInternal();
    155         ASSERT(m_state == RecordingState::Inactive);
    156         m_private->fetchData([this, pendingActivity = makePendingActivity(*this)](auto&& buffer, auto& mimeType) {
     162
     163    stopRecordingInternal();
     164    auto& privateRecorder = *m_private;
     165    privateRecorder.fetchData([this, pendingActivity = makePendingActivity(*this), privateRecorder = WTFMove(m_private)](auto&& buffer, auto& mimeType) {
     166        queueTaskKeepingObjectAlive(*this, TaskSource::Networking, [this, buffer = WTFMove(buffer), mimeType]() mutable {
    157167            if (!m_isActive)
    158168                return;
    159    
    160169            dispatchEvent(BlobEvent::create(eventNames().dataavailableEvent, Event::CanBubble::No, Event::IsCancelable::No, buffer ? Blob::create(buffer.releaseNonNull(), mimeType) : Blob::create()));
    161170
    162171            if (!m_isActive)
    163172                return;
    164 
    165173            dispatchEvent(Event::create(eventNames().stopEvent, Event::CanBubble::No, Event::IsCancelable::No));
    166174        });
     
    175183
    176184    m_private->fetchData([this, pendingActivity = makePendingActivity(*this)](auto&& buffer, auto& mimeType) {
    177         if (!m_isActive)
    178             return;
    179 
    180         dispatchEvent(BlobEvent::create(eventNames().dataavailableEvent, Event::CanBubble::No, Event::IsCancelable::No, buffer ? Blob::create(buffer.releaseNonNull(), mimeType) : Blob::create()));
     185        queueTaskKeepingObjectAlive(*this, TaskSource::Networking, [this, buffer = WTFMove(buffer), mimeType]() mutable {
     186            if (!m_isActive)
     187                return;
     188
     189            dispatchEvent(BlobEvent::create(eventNames().dataavailableEvent, Event::CanBubble::No, Event::IsCancelable::No, buffer ? Blob::create(buffer.releaseNonNull(), mimeType) : Blob::create()));
     190        });
    181191    });
    182192    return { };
  • trunk/Source/WebCore/Modules/mediarecorder/MediaRecorder.h

    r261553 r263511  
    7676
    7777private:
    78     MediaRecorder(Document&, Ref<MediaStream>&&, std::unique_ptr<MediaRecorderPrivate>&&, Options&& = { });
     78    MediaRecorder(Document&, Ref<MediaStream>&&, Options&& = { });
    7979
    8080    static std::unique_ptr<MediaRecorderPrivate> createMediaRecorderPrivate(Document&, MediaStreamPrivate&);
  • trunk/Source/WebCore/platform/mediarecorder/MediaRecorderPrivate.h

    r261553 r263511  
    6161    virtual void stopRecording() = 0;
    6262
    63     using ErrorCallback = Function<void(Optional<Exception>&&)>;
    64     void setErrorCallback(ErrorCallback&& errorCallback) { m_errorCallback = WTFMove(errorCallback); }
     63    using ErrorCallback = CompletionHandler<void(Optional<Exception>&&)>;
     64    virtual void startRecording(ErrorCallback&& callback) { callback({ }); }
    6565
    6666protected:
    6767    void setAudioSource(RefPtr<RealtimeMediaSource>&&);
    6868    void setVideoSource(RefPtr<RealtimeMediaSource>&&);
    69 
    70 protected:
    71     ErrorCallback m_errorCallback;
    7269
    7370private:
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.h

    r263026 r263511  
    6161
    6262    dispatch_queue_t m_serialDispatchQueue;
    63     CMTime m_lowWaterTime;
     63    CMTime m_lowWaterTime { kCMTimeInvalid };
    6464
    6565    RetainPtr<CMBufferQueueRef> m_outputBufferQueue;
     
    6767    bool m_isEncoding { false };
    6868
    69     RetainPtr<AudioConverterRef> m_converter;
     69    AudioConverterRef m_converter { nullptr };
    7070    AudioStreamBasicDescription m_sourceFormat;
    7171    AudioStreamBasicDescription m_destinationFormat;
     
    7575    Vector<AudioStreamPacketDescription> m_destinationPacketDescriptions;
    7676
    77     CMTime m_currentNativePresentationTimeStamp;
    78     CMTime m_currentOutputPresentationTimeStamp;
    79     CMTime m_remainingPrimeDuration;
     77    CMTime m_currentNativePresentationTimeStamp { kCMTimeInvalid };
     78    CMTime m_currentOutputPresentationTimeStamp { kCMTimeInvalid };
     79    CMTime m_remainingPrimeDuration { kCMTimeInvalid };
    8080
    8181    Vector<char> m_sourceBuffer;
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/AudioSampleBufferCompressor.mm

    r263026 r263511  
    5959{
    6060    dispatch_release(m_serialDispatchQueue);
     61    if (m_converter) {
     62        AudioConverterDispose(m_converter);
     63        m_converter = nullptr;
     64    }
    6165}
    6266
     
    113117        return false;
    114118    }
    115     m_converter = adoptCF(converter);
     119    m_converter = converter;
    116120
    117121    size_t cookieSize = 0;
    118122    const void *cookie = CMAudioFormatDescriptionGetMagicCookie(formatDescription, &cookieSize);
    119123    if (cookieSize) {
    120         if (auto error = AudioConverterSetProperty(m_converter.get(), kAudioConverterDecompressionMagicCookie, (UInt32)cookieSize, cookie)) {
     124        if (auto error = AudioConverterSetProperty(m_converter, kAudioConverterDecompressionMagicCookie, (UInt32)cookieSize, cookie)) {
    121125            RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor setting kAudioConverterDecompressionMagicCookie failed with %d", error);
    122126            return false;
     
    125129
    126130    size = sizeof(m_sourceFormat);
    127     if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioConverterCurrentInputStreamDescription, &size, &m_sourceFormat)) {
     131    if (auto error = AudioConverterGetProperty(m_converter, kAudioConverterCurrentInputStreamDescription, &size, &m_sourceFormat)) {
    128132        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioConverterCurrentInputStreamDescription failed with %d", error);
    129133        return false;
     
    136140
    137141    size = sizeof(m_destinationFormat);
    138     if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioConverterCurrentOutputStreamDescription, &size, &m_destinationFormat)) {
     142    if (auto error = AudioConverterGetProperty(m_converter, kAudioConverterCurrentOutputStreamDescription, &size, &m_destinationFormat)) {
    139143        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioConverterCurrentOutputStreamDescription failed with %d", error);
    140144        return false;
     
    150154
    151155        size = sizeof(outputBitRate);
    152         if (auto error = AudioConverterSetProperty(m_converter.get(), kAudioConverterEncodeBitRate, size, &outputBitRate)) {
     156        if (auto error = AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, size, &outputBitRate)) {
    153157            RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor setting kAudioConverterEncodeBitRate failed with %d", error);
    154158            return false;
     
    160164        size = sizeof(m_maxOutputPacketSize);
    161165
    162         if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioConverterPropertyMaximumOutputPacketSize, &size, &m_maxOutputPacketSize)) {
     166        if (auto error = AudioConverterGetProperty(m_converter, kAudioConverterPropertyMaximumOutputPacketSize, &size, &m_maxOutputPacketSize)) {
    163167            RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioConverterPropertyMaximumOutputPacketSize failed with %d", error);
    164168            return false;
     
    190194        UInt32 size = sizeof(primeInfo);
    191195
    192         if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioConverterPrimeInfo, &size, &primeInfo)) {
     196        if (auto error = AudioConverterGetProperty(m_converter, kAudioConverterPrimeInfo, &size, &primeInfo)) {
    193197            RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioConverterPrimeInfo failed with %d", error);
    194198            return;
     
    212216    UInt32 delaySize = sizeof(uint32_t);
    213217    uint32_t originalDelayMode = 0;
    214     if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioCodecPropertyDelayMode, &delaySize, &originalDelayMode)) {
     218    if (auto error = AudioConverterGetProperty(m_converter, kAudioCodecPropertyDelayMode, &delaySize, &originalDelayMode)) {
    215219        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioCodecPropertyDelayMode failed with %d", error);
    216220        return nil;
     
    218222
    219223    uint32_t optimalDelayMode = kAudioCodecDelayMode_Optimal;
    220     if (auto error = AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertyDelayMode, delaySize, &optimalDelayMode)) {
     224    if (auto error = AudioConverterSetProperty(m_converter, kAudioCodecPropertyDelayMode, delaySize, &optimalDelayMode)) {
    221225        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor setting kAudioCodecPropertyDelayMode failed with %d", error);
    222226        return nil;
     
    225229    UInt32 primeSize = sizeof(AudioCodecPrimeInfo);
    226230    AudioCodecPrimeInfo primeInfo { 0, 0 };
    227     if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioCodecPropertyPrimeInfo, &primeSize, &primeInfo)) {
     231    if (auto error = AudioConverterGetProperty(m_converter, kAudioCodecPropertyPrimeInfo, &primeSize, &primeInfo)) {
    228232        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioCodecPropertyPrimeInfo failed with %d", error);
    229233        return nil;
    230234    }
    231235
    232     if (auto error = AudioConverterSetProperty(m_converter.get(), kAudioCodecPropertyDelayMode, delaySize, &originalDelayMode)) {
     236    if (auto error = AudioConverterSetProperty(m_converter, kAudioCodecPropertyDelayMode, delaySize, &originalDelayMode)) {
    233237        RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor setting kAudioCodecPropertyDelayMode failed with %d", error);
    234238        return nil;
     
    243247        UInt32 cookieSize = 0;
    244248
    245         auto error = AudioConverterGetPropertyInfo(m_converter.get(), kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
     249        auto error = AudioConverterGetPropertyInfo(m_converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
    246250        if ((error == noErr) && !!cookieSize) {
    247251            cookie.resize(cookieSize);
    248252
    249             if (auto error = AudioConverterGetProperty(m_converter.get(), kAudioConverterCompressionMagicCookie, &cookieSize, cookie.data())) {
     253            if (auto error = AudioConverterGetProperty(m_converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie.data())) {
    250254                RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor getting kAudioConverterCompressionMagicCookie failed with %d", error);
    251255                return nil;
     
    440444        UInt32 numOutputPackets = (UInt32)m_destinationBuffer.capacity() / outputPacketSize;
    441445
    442         auto error = AudioConverterFillComplexBuffer(m_converter.get(), audioConverterComplexInputDataProc, this, &numOutputPackets, &fillBufferList, m_destinationPacketDescriptions.data());
     446        auto error = AudioConverterFillComplexBuffer(m_converter, audioConverterComplexInputDataProc, this, &numOutputPackets, &fillBufferList, m_destinationPacketDescriptions.data());
    443447        if (error) {
    444448            RELEASE_LOG_ERROR(MediaStream, "AudioSampleBufferCompressor AudioConverterFillComplexBuffer failed with %d", error);
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h

    r263026 r263511  
    115115    std::unique_ptr<VideoSampleBufferCompressor> m_videoCompressor;
    116116    RetainPtr<AVAssetWriterInput> m_videoAssetWriterInput;
    117     CMTime m_lastVideoPresentationTime;
    118     CMTime m_lastVideoDecodingTime;
     117    CMTime m_lastVideoPresentationTime { kCMTimeInvalid };
     118    CMTime m_lastVideoDecodingTime { kCMTimeInvalid };
    119119    bool m_hasEncodedVideoSamples { false };
    120120
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm

    r263084 r263511  
    436436    // We hop to the main thread since finishing the video compressor might trigger starting the writer asynchronously.
    437437    callOnMainThread([this, weakThis = makeWeakPtr(this)]() mutable {
    438         auto whenFinished = [this] {
     438        auto whenFinished = [this, weakThis] {
     439            if (!weakThis)
     440                return;
     441
    439442            m_isStopping = false;
    440             if (m_fetchDataCompletionHandler) {
    441                 auto buffer = WTFMove(m_data);
    442                 m_fetchDataCompletionHandler(WTFMove(buffer));
    443             }
    444 
    445443            m_isStopped = false;
    446444            m_hasStartedWriting = false;
    447             clear();
     445
     446            if (m_writer)
     447                m_writer.clear();
     448            if (m_fetchDataCompletionHandler)
     449                m_fetchDataCompletionHandler(std::exchange(m_data, nullptr));
    448450        };
    449451
     
    462464            ALLOW_DEPRECATED_DECLARATIONS_END
    463465
    464             [m_writer finishWritingWithCompletionHandler:[weakThis = WTFMove(weakThis), whenFinished = WTFMove(whenFinished)]() mutable {
    465                 callOnMainThread([weakThis = WTFMove(weakThis), whenFinished = WTFMove(whenFinished)]() mutable {
    466                     if (!weakThis)
    467                         return;
    468                     whenFinished();
    469                 });
     466            [m_writer finishWritingWithCompletionHandler:[whenFinished = WTFMove(whenFinished)]() mutable {
     467                callOnMainThread(WTFMove(whenFinished));
    470468            }];
    471469        });
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm

    r263026 r263511  
    5757{
    5858    dispatch_release(m_serialDispatchQueue);
     59    if (m_vtSession) {
     60        VTCompressionSessionInvalidate(m_vtSession.get());
     61        m_vtSession = nullptr;
     62    }
    5963}
    6064
  • trunk/Source/WebKit/ChangeLog

    r263500 r263511  
     12020-06-25  Youenn Fablet  <youenn@apple.com>
     2
     3        MediaRecorder stopRecorder() returns empty Blob after first use
     4        https://bugs.webkit.org/show_bug.cgi?id=212274
     5        <rdar://problem/63601298>
     6
     7        Reviewed by Eric Carlson.
     8
     9        Update implementation to do initialization as part of startRecording.
     10
     11        * GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
     12        (WebKit::RemoteMediaRecorderManager::releaseRecorder):
     13        Remove ASSERT as recorder creation in WebProcess is always ok while creation in GPUProcess may fail and m_recorders may not be populated.
     14        * WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp:
     15        (WebKit::MediaRecorderPrivate::MediaRecorderPrivate):
     16        (WebKit::MediaRecorderPrivate::startRecording):
     17        * WebProcess/GPU/webrtc/MediaRecorderPrivate.h:
     18
    1192020-06-24  James Savage  <james.savage@apple.com>
    220
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp

    r262708 r263511  
    6565void RemoteMediaRecorderManager::releaseRecorder(MediaRecorderIdentifier identifier)
    6666{
    67     ASSERT(m_recorders.contains(identifier));
    6867    m_recorders.remove(identifier);
    6968}
  • trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.cpp

    r262708 r263511  
    4646MediaRecorderPrivate::MediaRecorderPrivate(MediaStreamPrivate& stream)
    4747    : m_identifier(MediaRecorderIdentifier::generate())
     48    , m_stream(makeRef(stream))
    4849    , m_connection(WebProcess::singleton().ensureGPUProcessConnection().connection())
     50{
     51}
     52
     53void MediaRecorderPrivate::startRecording(ErrorCallback&& errorCallback)
    4954{
    5055    // FIXME: we will need to implement support for multiple audio/video tracks
    5156    // Currently we only choose the first track as the recorded track.
    5257
    53     auto selectedTracks = MediaRecorderPrivate::selectTracks(stream);
     58    auto selectedTracks = MediaRecorderPrivate::selectTracks(m_stream);
    5459    if (selectedTracks.audioTrack) {
    5560        m_ringBuffer = makeUnique<CARingBuffer>(makeUniqueRef<SharedRingBufferStorage>(this));
     
    6570    }
    6671
    67     m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorderManager::CreateRecorder { m_identifier, !!selectedTracks.audioTrack, width, height }, [this, weakThis = makeWeakPtr(this), audioTrack = makeRefPtr(selectedTracks.audioTrack), videoTrack = makeRefPtr(selectedTracks.videoTrack)](auto&& exception) {
    68         if (!weakThis)
     72    m_connection->sendWithAsyncReply(Messages::RemoteMediaRecorderManager::CreateRecorder { m_identifier, !!selectedTracks.audioTrack, width, height }, [this, weakThis = makeWeakPtr(this), audioTrack = makeRefPtr(selectedTracks.audioTrack), videoTrack = makeRefPtr(selectedTracks.videoTrack), errorCallback = WTFMove(errorCallback)](auto&& exception) mutable {
     73        if (!weakThis) {
     74            errorCallback({ });
    6975            return;
    70         if (exception)
    71             return m_errorCallback(Exception { exception->code, WTFMove(exception->message) });
     76        }
     77        if (exception) {
     78            errorCallback(Exception { exception->code, WTFMove(exception->message) });
     79            return;
     80        }
    7281        if (audioTrack)
    7382            setAudioSource(&audioTrack->source());
    7483        if (videoTrack)
    7584            setVideoSource(&videoTrack->source());
     85        errorCallback({ });
    7686    }, 0);
    7787}
  • trunk/Source/WebKit/WebProcess/GPU/webrtc/MediaRecorderPrivate.h

    r262708 r263511  
    5959    void fetchData(CompletionHandler<void(RefPtr<WebCore::SharedBuffer>&&, const String& mimeType)>&&) final;
    6060    void stopRecording() final;
     61    void startRecording(ErrorCallback&&) final;
    6162    void audioSamplesAvailable(const WTF::MediaTime&, const WebCore::PlatformAudioData&, const WebCore::AudioStreamDescription&, size_t) final;
    6263
     
    6566
    6667    MediaRecorderIdentifier m_identifier;
     68    Ref<MediaStreamPrivate> m_stream;
     69    Ref<IPC::Connection> m_connection;
    6770
    68     Ref<IPC::Connection> m_connection;
    6971    String m_recordedAudioTrackID;
    7072    String m_recordedVideoTrackID;
Note: See TracChangeset for help on using the changeset viewer.