Changeset 279542 in webkit
- Timestamp:
- Jul 3, 2021 12:01:52 AM (13 months ago)
- Location:
- trunk
- Files:
-
- 6 added
- 16 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/media/media-source/content/test-fragmented-video-manifest.json (added)
-
LayoutTests/media/media-source/content/test-fragmented-video.mp4 (added)
-
LayoutTests/media/media-source/media-mp4-h264-partial-abort-expected.txt (added)
-
LayoutTests/media/media-source/media-mp4-h264-partial-abort.html (added)
-
LayoutTests/media/media-source/media-webm-opus-partial-abort-expected.txt (added)
-
LayoutTests/media/media-source/media-webm-opus-partial-abort.html (added)
-
LayoutTests/media/media-source/media-webm-opus-partial.html (modified) (1 diff)
-
LayoutTests/media/media-source/media-webm-vorbis-partial.html (modified) (1 diff)
-
LayoutTests/platform/mac/TestExpectations (modified) (2 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm (modified) (1 diff)
-
Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVStreamSession.mm (modified) (3 diffs)
-
Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm (modified) (2 diffs)
-
Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h (modified) (2 diffs)
-
Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm (modified) (4 diffs)
-
Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (modified) (5 diffs)
-
Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (modified) (15 diffs)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParser.cpp (modified) (1 diff)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParser.h (modified) (2 diffs)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp (modified) (8 diffs)
-
Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r279522 r279542 1 2021-07-03 Jean-Yves Avenard <jya@apple.com> 2 3 SourceBuffer.abort() doesn't go back to state WAITING_FOR_SEGMENT properly 4 https://bugs.webkit.org/show_bug.cgi?id=227559 5 <rdar://problem/79996056> 6 7 Reviewed by Eric Carlson. 8 9 * media/media-source/content/test-fragmented-video-manifest.json: Added. 10 * media/media-source/content/test-fragmented-video.mp4: Added. 11 * media/media-source/media-mp4-h264-partial-abort-expected.txt: Added. 12 * media/media-source/media-mp4-h264-partial-abort.html: Added. 13 * media/media-source/media-webm-opus-partial-abort-expected.txt: Added. 14 * media/media-source/media-webm-opus-partial-abort.html: Added. 15 * media/media-source/media-webm-opus-partial.html: fix title. 16 * media/media-source/media-webm-vorbis-partial.html: fix title. 17 * platform/mac/TestExpectations: 18 1 19 2021-07-02 Eric Hutchison <ehutchison@apple.com> 2 20 -
trunk/LayoutTests/media/media-source/media-webm-opus-partial.html
r279492 r279542 2 2 <html> 3 3 <head> 4 <title>media- opus-partial</title>4 <title>media-webm-opus-partial</title> 5 5 <script src="../../media/media-source/media-source-loader.js"></script> 6 6 <script src="../../media/video-test.js"></script> -
trunk/LayoutTests/media/media-source/media-webm-vorbis-partial.html
r279492 r279542 2 2 <html> 3 3 <head> 4 <title>media- vorbis-partial</title>4 <title>media-webm-vorbis-partial</title> 5 5 <script src="../../media/media-source/media-source-loader.js"></script> 6 6 <script src="../../media/video-test.js"></script> -
trunk/LayoutTests/platform/mac/TestExpectations
r279516 r279542 1769 1769 # These tests require macOS Monterey. 1770 1770 [ Catalina Mojave BigSur ] media/media-source/media-webm-vorbis-partial.html [ Skip ] 1771 [ Catalina Mojave BigSur ] media/media-source/media-source-webm-vorbis-partial.html [ Skip ] 1771 1772 [ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial.html [ Skip ] 1773 [ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial-abort.html [ Skip ] 1772 1774 1773 1775 webkit.org/b/214422 imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html [ Pass Failure ] … … 2164 2166 2165 2167 webkit.org/b/222573 media/media-fullscreen-pause-inline.html [ Pass Failure ] 2166 2167 webkit.org/b/222495 media/media-source/media-source-webm-vorbis-partial.html [ Failure ]2168 2168 2169 2169 webkit.org/b/222692 inspector/page/empty-or-missing-resources.html [ Pass Timeout ] -
trunk/Source/WebCore/ChangeLog
r279530 r279542 1 2021-07-03 Jean-Yves Avenard <jya@apple.com> 2 3 SourceBuffer.abort() doesn't go back to state WAITING_FOR_SEGMENT properly 4 https://bugs.webkit.org/show_bug.cgi?id=227559 5 <rdar://problem/79996056> 6 7 Reviewed by Eric Carlson. 8 9 Per spec, calling sourcebuffer.abort method should allow you to add a new segment 10 immediately after, as abort moves the append state back to WAITING_FOR_SEGMENT. 11 A segment can be either an init segment or a media segment. 12 We used to discard all further content until an init segment was encountered. 13 This could be problematic due to the typical use case of abort: 14 1- Seek to a location 15 2- Append a partial media segment long enough to finish seeking and display the 16 new content at the new position. 17 If multiple seeks were done in rapid succession, abort() is called right after 18 before starting the new seek so that we can add the new segment, regardless of what 19 was appended before. 20 YouTube applies a workaround for Safari where it will always append an init segment 21 after calling abort, this is different to what they do with Firefox (and likely Chrome). 22 To be able to resume after appending a partial media segment we must ensure that the 23 SourceBufferParser is always left in a sane context, and not be interrupted at some 24 random points. The abort() call used to interrupt the buffer parsing on the fly and 25 then reset things which would require a new init segment to restart. 26 Instead we always fully parse the pending buffer received befofe the call to abort. 27 The SourceBufferParserAVFObjC could already properly deal with discontinuity unlike 28 SourceBufferParserWebM. 29 To ensure that buffers sent after the call to abort() are only ever processed once 30 the pending ones have been parsed, and in order to avoid having blocking calls 31 we play with the order in which tasks are scheduled. 32 33 Fly-by fixes: 34 - The SourceBufferParser handle two types of parser: SourceBufferParser and the 35 platform specific AVStreamDataParser. Rename the accessor method to more clearly 36 differentate which parser we are dealing with. 37 - The SourceBufferParserWebM and SourceBufferPrivateAVFObjC used different task dispatching 38 mechanisms. We make them both share the same one now found in the base class. 39 40 Tests: media/media-source/media-mp4-h264-partial-abort.html 41 media/media-source/media-webm-opus-partial-abort.html 42 43 * platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm: 44 (WebCore::CDMSessionAVContentKeySession::~CDMSessionAVContentKeySession): rename method. 45 * platform/graphics/avfoundation/objc/CDMSessionAVStreamSession.mm: 46 (WebCore::CDMSessionAVStreamSession::~CDMSessionAVStreamSession): rename method. 47 (WebCore::CDMSessionAVStreamSession::update): rename method. 48 * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm: rename method. 49 (WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer): rename method. 50 (WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer): rename method. 51 * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h: rename method, remove 52 now unused member. 53 * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm: 54 (WebCore::SourceBufferPrivateAVFObjC::removeCodedFrames): Postpone call to ensure 55 we are running the remove frame algorithm once all pending frames have been processed. 56 (WebCore::SourceBufferParserAVFObjC::resetParserState): Remove use of m_discardSamplesUntilNextInitializationSegment. 57 (WebCore::SourceBufferParserAVFObjC::didParseStreamDataAsAsset): Change to base dispatch method. 58 (WebCore::SourceBufferParserAVFObjC::didFailToParseStreamDataWithError): Change to base dispatch method. 59 (WebCore::SourceBufferParserAVFObjC::didProvideMediaDataForTrackID): Change to base dispatch method. 60 * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h: Rename methods. Remove no longer used 61 members. 62 * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm: 63 (WebCore::SourceBufferPrivateAVFObjC::~SourceBufferPrivateAVFObjC): 64 (WebCore::SourceBufferPrivateAVFObjC::didParseInitializationData): No longer use a Cancellable task 65 as we never cancel it anymore. 66 (WebCore::SourceBufferPrivateAVFObjC::append): re-schedule the append task immediately to ensure 67 that processed packets flushed on the parser queue during abort are handled in the right order on 68 the main thread. 69 (WebCore::SourceBufferPrivateAVFObjC::appendCompleted): Check that abort wasn't called since append started 70 to ensure that no updateend event is incorrectly fired twice. 71 (WebCore::SourceBufferPrivateAVFObjC::abort): Abort is now a no-op that only set the m_abortCalled member. 72 (WebCore::SourceBufferPrivateAVFObjC::resetParserState): Change the order of operations so that the 73 SourceBufferParser is only reset after it has finished processing its data. 74 (WebCore::SourceBufferPrivateAVFObjC::destroyStreamDataParser): Use rename method. 75 (WebCore::SourceBufferPrivateAVFObjC::removedFromMediaSource): Use rename method. 76 (WebCore::SourceBufferPrivateAVFObjC::streamDataParser const): Renamed method from "parser" 77 (WebCore::SourceBufferPrivateAVFObjC::attemptToDecrypt): Use renamed method. 78 * platform/graphics/cocoa/SourceBufferParser.cpp: 79 (WebCore::callOnMainThreadCallback): Move dispatch method from SourceBufferParserWebM 80 (WebCore::SourceBufferParser::setCallOnClientThreadCallback): 81 (WebCore::SourceBufferParser::SourceBufferParser): 82 * platform/graphics/cocoa/SourceBufferParser.h: 83 * platform/graphics/cocoa/SourceBufferParserWebM.cpp: 84 (WebCore::SourceBufferParserWebM::SourceBufferParserWebM): 85 (WebCore::SourceBufferParserWebM::resetParserState): Don't clear the data set by parsing 86 the previous init segment. Set the parsing state to waiting for a new segment if an 87 init segment has been fully parsed. 88 (WebCore::SourceBufferParserWebM::OnElementEnd): 89 (WebCore::SourceBufferParserWebM::OnEbml): 90 (WebCore::SourceBufferParserWebM::VideoTrackData::reset): 91 (WebCore::SourceBufferParserWebM::VideoTrackData::consumeFrameData): 92 (WebCore::SourceBufferParserWebM::AudioTrackData::reset): 93 * platform/graphics/cocoa/SourceBufferParserWebM.h: 94 1 95 2021-07-02 Joonghun Park <jh718.park@samsung.com> 2 96 -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm
r277449 r279542 121 121 122 122 for (auto& sourceBuffer : m_sourceBuffers) 123 removeParser(sourceBuffer-> parser());123 removeParser(sourceBuffer->streamDataParser()); 124 124 } 125 125 -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVStreamSession.mm
r264710 r279542 97 97 98 98 for (auto& sourceBuffer : m_sourceBuffers) 99 removeParser(sourceBuffer-> parser());99 removeParser(sourceBuffer->streamDataParser()); 100 100 } 101 101 … … 235 235 NSError* error = nil; 236 236 ALLOW_DEPRECATED_DECLARATIONS_BEGIN 237 RetainPtr<NSData> request = [protectedSourceBuffer-> parser() streamingContentKeyRequestDataForApp:certificateData.get() contentIdentifier:initData.get() trackID:protectedSourceBuffer->protectedTrackID() options:options.get() error:&error];237 RetainPtr<NSData> request = [protectedSourceBuffer->streamDataParser() streamingContentKeyRequestDataForApp:certificateData.get() contentIdentifier:initData.get() trackID:protectedSourceBuffer->protectedTrackID() options:options.get() error:&error]; 238 238 ALLOW_DEPRECATED_DECLARATIONS_END 239 239 240 if (![protectedSourceBuffer-> parser() respondsToSelector:@selector(contentProtectionSessionIdentifier)])240 if (![protectedSourceBuffer->streamDataParser() respondsToSelector:@selector(contentProtectionSessionIdentifier)]) 241 241 m_sessionId = createCanonicalUUIDString(); 242 242 … … 264 264 RetainPtr<NSData> keyData = adoptNS([[NSData alloc] initWithBytes:key->data() length:key->length()]); 265 265 ALLOW_DEPRECATED_DECLARATIONS_BEGIN 266 [protectedSourceBuffer-> parser() processContentKeyResponseData:keyData.get() forTrackID:protectedSourceBuffer->protectedTrackID()];266 [protectedSourceBuffer->streamDataParser() processContentKeyResponseData:keyData.get() forTrackID:protectedSourceBuffer->protectedTrackID()]; 267 267 ALLOW_DEPRECATED_DECLARATIONS_END 268 268 -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm
r240437 r279542 84 84 ASSERT(sourceBuffer); 85 85 86 addParser(sourceBuffer-> parser());86 addParser(sourceBuffer->streamDataParser()); 87 87 88 88 m_sourceBuffers.append(sourceBuffer); … … 95 95 ASSERT(sourceBuffer); 96 96 97 removeParser(sourceBuffer-> parser());97 removeParser(sourceBuffer->streamDataParser()); 98 98 99 99 sourceBuffer->unregisterForErrorNotifications(this); -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h
r272039 r279542 51 51 virtual ~SourceBufferParserAVFObjC(); 52 52 53 AVStreamDataParser* parser() const { return m_parser.get(); }53 AVStreamDataParser* streamDataParser() const { return m_parser.get(); } 54 54 55 55 Type type() const { return Type::AVFObjC; } … … 78 78 RetainPtr<AVStreamDataParser> m_parser; 79 79 RetainPtr<WebAVStreamDataParserListener> m_delegate; 80 bool m_discardSamplesUntilNextInitializationSegment { false };81 80 bool m_parserStateWasReset { false }; 82 81 -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm
r278253 r279542 242 242 { 243 243 m_parserStateWasReset = true; 244 m_discardSamplesUntilNextInitializationSegment = true;245 244 } 246 245 … … 262 261 void SourceBufferParserAVFObjC::didParseStreamDataAsAsset(AVAsset* asset) 263 262 { 264 callOnMainThread([this, strongThis = makeRef(*this), asset = retainPtr(asset)] { 265 m_discardSamplesUntilNextInitializationSegment = false; 266 263 m_callOnClientThreadCallback([this, strongThis = makeRef(*this), asset = retainPtr(asset)] { 267 264 if (!m_didParseInitializationDataCallback) 268 265 return; … … 305 302 void SourceBufferParserAVFObjC::didFailToParseStreamDataWithError(NSError* error) 306 303 { 307 callOnMainThread([this, strongThis = makeRef(*this), error = retainPtr(error)] {304 m_callOnClientThreadCallback([this, strongThis = makeRef(*this), error = retainPtr(error)] { 308 305 if (m_didEncounterErrorDuringParsingCallback) 309 306 m_didEncounterErrorDuringParsingCallback(error.get().code); … … 314 311 { 315 312 UNUSED_PARAM(flags); 316 callOnMainThread([this, strongThis = makeRef(*this), sampleBuffer = retainPtr(sampleBuffer), trackID, mediaType = mediaType] {313 m_callOnClientThreadCallback([this, strongThis = makeRef(*this), sampleBuffer = retainPtr(sampleBuffer), trackID, mediaType = mediaType] { 317 314 if (!m_didProvideMediaDataCallback) 318 return;319 320 if (m_discardSamplesUntilNextInitializationSegment)321 315 return; 322 316 -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h
r278580 r279542 103 103 104 104 uint64_t protectedTrackID() const { return m_protectedTrackID; } 105 AVStreamDataParser* parser() const;105 AVStreamDataParser* streamDataParser() const; 106 106 void setCDMSession(CDMSessionMediaSourceAVFObjC*); 107 107 void setCDMInstance(CDMInstance*); … … 151 151 // SourceBufferPrivate overrides 152 152 void append(Vector<unsigned char>&&) final; 153 void removeCodedFrames(const MediaTime& start, const MediaTime& end, const MediaTime& currentMediaTime, bool isEnded, CompletionHandler<void()>&&) final; 153 154 void abort() final; 154 155 void resetParserState() final; … … 173 174 void didBecomeReadyForMoreSamples(uint64_t trackID); 174 175 void appendCompleted(); 175 void destroy Parser();176 void destroyStreamDataParser(); 176 177 void destroyRenderers(); 177 178 void clearTracks(); … … 194 195 bool m_hasPendingAppendCompletedCallback { false }; 195 196 Vector<std::pair<uint64_t, Ref<MediaSample>>> m_mediaSamples; 196 TaskCancellationGroup m_mediaSampleTaskCancellationGroup;197 197 198 198 RetainPtr<AVSampleBufferDisplayLayer> m_displayLayer; … … 228 228 uint64_t m_protectedTrackID { notFound }; 229 229 uint64_t m_mapID; 230 bool m_abortCalled { false }; 230 231 231 232 #if !RELEASE_LOG_DISABLED -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
r279335 r279542 349 349 ASSERT(!m_client); 350 350 sourceBufferMap().remove(m_mapID); 351 destroy Parser();351 destroyStreamDataParser(); 352 352 destroyRenderers(); 353 353 clearTracks(); … … 356 356 PAL::CMNotificationCenterRemoveListener(PAL::CMNotificationCenterGetDefaultLocalCenter(), this, bufferWasConsumedCallback, PAL::kCMSampleBufferConsumerNotification_BufferConsumed, nullptr); 357 357 358 if (m_hasSessionSemaphore) 359 m_hasSessionSemaphore->signal(); 360 361 m_mediaSampleTaskCancellationGroup.cancel(); 358 resetParserState(); 362 359 } 363 360 … … 418 415 } 419 416 420 callOnMainThread( CancellableTask(m_mediaSampleTaskCancellationGroup,[this, weakThis = WTFMove(weakThis)] {417 callOnMainThread([this, weakThis = WTFMove(weakThis)] { 421 418 if (!weakThis) 422 419 return; … … 439 436 appendCompleted(); 440 437 } 441 }) );438 }); 442 439 }); 443 440 } … … 482 479 m_protectedTrackID = trackID; 483 480 484 auto parser = this-> parser();481 auto parser = this->streamDataParser(); 485 482 if (!parser) 486 483 return; … … 515 512 m_mediaSource->sourceBufferKeyNeeded(this, m_initData.get()); 516 513 if (auto session = player->cdmSession()) { 517 if (auto parser = this-> parser())514 if (auto parser = this->streamDataParser()) 518 515 session->addParser(parser); 519 516 hasSessionSemaphore->signal(); … … 534 531 if (m_cdmInstance) { 535 532 if (auto instanceSession = m_cdmInstance->sessionForKeyIDs(keyIDs.value())) { 536 if (auto parser = this-> parser())533 if (auto parser = this->streamDataParser()) 537 534 [instanceSession->contentKeySession() addContentKeyRecipient:parser]; 538 535 if (m_hasSessionSemaphore) { … … 571 568 ALWAYS_LOG(LOGIDENTIFIER, "data length = ", data.size()); 572 569 573 ASSERT(!m_hasSessionSemaphore); 574 ASSERT(!m_abortSemaphore); 575 576 if (m_client) 577 m_client->sourceBufferPrivateReportExtraMemoryCost(totalTrackBufferSizeInBytes()); 578 579 m_abortSemaphore = Box<Semaphore>::create(0); 580 m_parser->setWillProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore] (uint64_t trackID) mutable { 581 // We must call synchronously to the main thread, as the AVStreamSession must be associated 582 // with the streamDataParser before the delegate method returns. 583 Box<BinarySemaphore> respondedSemaphore = Box<BinarySemaphore>::create(); 584 callOnMainThread([weakThis = WTFMove(weakThis), trackID, respondedSemaphore]() { 585 if (weakThis) 586 weakThis->willProvideContentKeyRequestInitializationDataForTrackID(trackID); 587 respondedSemaphore->signal(); 570 // Queue a task to preserve the ordering of operations started by the 571 // abort process and ensure that the new appendBuffer will only 572 // ever deal with a sane parsing context. 573 callOnMainThread([weakThis = makeWeakPtr(*this), data = WTFMove(data), this]() mutable { 574 if (!weakThis) 575 return; 576 577 ASSERT(!m_hasSessionSemaphore); 578 ASSERT(!m_abortSemaphore); 579 580 if (m_client) 581 m_client->sourceBufferPrivateReportExtraMemoryCost(totalTrackBufferSizeInBytes()); 582 583 m_abortSemaphore = Box<Semaphore>::create(0); 584 m_parser->setWillProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis, abortSemaphore = m_abortSemaphore](uint64_t trackID) mutable { 585 // We must call synchronously to the main thread, as the AVStreamSession must be associated 586 // with the streamDataParser before the delegate method returns. 587 Box<BinarySemaphore> respondedSemaphore = Box<BinarySemaphore>::create(); 588 callOnMainThread([weakThis = WTFMove(weakThis), trackID, respondedSemaphore]() { 589 if (weakThis) 590 weakThis->willProvideContentKeyRequestInitializationDataForTrackID(trackID); 591 respondedSemaphore->signal(); 592 }); 593 594 while (true) { 595 if (respondedSemaphore->waitFor(100_ms)) 596 return; 597 598 if (abortSemaphore->waitFor(100_ms)) { 599 abortSemaphore->signal(); 600 return; 601 } 602 } 588 603 }); 589 604 590 while (true) { 591 if (respondedSemaphore->waitFor(100_ms)) 592 return; 593 594 if (abortSemaphore->waitFor(100_ms)) { 595 abortSemaphore->signal(); 596 return; 605 m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis, abortSemaphore = m_abortSemaphore](Ref<Uint8Array>&& initData, uint64_t trackID) mutable { 606 // Called on the data parser queue. 607 Box<BinarySemaphore> hasSessionSemaphore = Box<BinarySemaphore>::create(); 608 callOnMainThread([weakThis = WTFMove(weakThis), initData = WTFMove(initData), trackID, hasSessionSemaphore]() mutable { 609 if (weakThis) 610 weakThis->didProvideContentKeyRequestInitializationDataForTrackID(WTFMove(initData), trackID, hasSessionSemaphore); 611 }); 612 613 while (true) { 614 if (hasSessionSemaphore->waitFor(100_ms)) 615 return; 616 617 if (abortSemaphore->waitFor(100_ms)) { 618 abortSemaphore->signal(); 619 return; 620 } 597 621 } 598 }599 });600 601 m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore] (Ref<Uint8Array>&& initData, uint64_t trackID) mutable {602 Box<BinarySemaphore> hasSessionSemaphore = Box<BinarySemaphore>::create();603 callOnMainThread([weakThis = WTFMove(weakThis), initData = WTFMove(initData), trackID, hasSessionSemaphore] () mutable {604 if (weakThis)605 weakThis->didProvideContentKeyRequestInitializationDataForTrackID(WTFMove(initData), trackID, hasSessionSemaphore);606 622 }); 607 623 608 while (true) { 609 if (hasSessionSemaphore->waitFor(100_ms)) 610 return; 611 612 if (abortSemaphore->waitFor(100_ms)) { 613 abortSemaphore->signal(); 614 return; 615 } 616 } 617 }); 618 619 m_parsingSucceeded = true; 620 dispatch_group_enter(m_isAppendingGroup.get()); 621 622 dispatch_async(globalDataParserQueue(), [data = WTFMove(data), weakThis = m_appendWeakFactory.createWeakPtr(*this), parser = m_parser, isAppendingGroup = m_isAppendingGroup]() mutable { 623 parser->appendData(WTFMove(data), [weakThis = WTFMove(weakThis)]() mutable { 624 callOnMainThread([weakThis = WTFMove(weakThis)] { 624 m_parsingSucceeded = true; 625 dispatch_group_enter(m_isAppendingGroup.get()); 626 627 dispatch_async(globalDataParserQueue(), [data = WTFMove(data), weakThis = m_appendWeakFactory.createWeakPtr(*this), parser = m_parser, isAppendingGroup = m_isAppendingGroup]() mutable { 628 parser->appendData(WTFMove(data), [weakThis = WTFMove(weakThis)]() mutable { 629 callOnMainThread([weakThis = WTFMove(weakThis)] { 625 630 if (!weakThis) 626 631 return; … … 632 637 633 638 weakThis->appendCompleted(); 639 }); 634 640 }); 641 dispatch_group_leave(isAppendingGroup.get()); 635 642 }); 636 dispatch_group_leave(isAppendingGroup.get());637 643 }); 638 644 } … … 651 657 } 652 658 659 if (m_abortCalled) 660 return; 661 653 662 if (auto player = this->player(); player && m_parsingSucceeded) 654 663 player->setLoadingProgresssed(true); … … 657 666 } 658 667 668 void SourceBufferPrivateAVFObjC::removeCodedFrames(const MediaTime& start, const MediaTime& end, const MediaTime& currentMediaTime, bool isEnded, CompletionHandler<void()>&& completionHandler) 669 { 670 // Queue a task to preserve the ordering of operations started by any 671 // earlier call to abort and that pending frames will be removed if needed. 672 callOnMainThread([weakThis = makeWeakPtr(*this), start, end, currentMediaTime, isEnded, completionHandler = WTFMove(completionHandler)]() mutable { 673 if (!weakThis) { 674 completionHandler(); 675 return; 676 } 677 weakThis->SourceBufferPrivate::removeCodedFrames(start, end, currentMediaTime, isEnded, WTFMove(completionHandler)); 678 }); 679 } 680 681 // The MSE spec requires that we abort the current buffer append algorithm 682 // https://w3c.github.io/media-source/#dfn-buffer-append 683 // which is then followed by a call to resetParserState 684 // as per https://w3c.github.io/media-source/#dom-sourcebuffer-abort 685 // However due to our asynchronous design this causes inherent difficulties. 686 // The SourceBuffe's abortIfUpdating method would have already cancelled any 687 // pending update not yet despatched by its timer. 688 // As the spec behaviour is non deterministic anyway, we instead process all 689 // pending frames found in the input buffer. 659 690 void SourceBufferPrivateAVFObjC::abort() 660 691 { 661 692 ALWAYS_LOG(LOGIDENTIFIER); 662 693 663 // The parsing queue may be blocked waiting for the main thread to provide it a AVStreamSession. We 694 // Queue a task to preserve the ordering of operations started by any 695 // earlier call to abort. 696 callOnMainThread([weakThis = makeWeakPtr(*this), this]() { 697 if (!weakThis) 698 return; 699 ASSERT(!m_abortCalled, "Abort should only be called if we were currently updating, resetParserState must have been called in between"); 700 m_abortCalled = true; 701 }); 702 } 703 704 void SourceBufferPrivateAVFObjC::resetParserState() 705 { 706 ALWAYS_LOG(LOGIDENTIFIER); 707 708 // The parsing queue may be blocked waiting for the main thread to provide it an AVStreamSession. We 664 709 // were asked to abort, and that cancels all outstanding append operations. Without cancelling this 665 710 // semaphore, the m_isAppendingGroup wait operation will deadlock. … … 673 718 } 674 719 675 m_parser->resetParserState(); 676 m_mediaSamples.clear(); 677 m_initializationSegmentIsHandled = false; 678 m_mediaSampleTaskCancellationGroup.cancel(); 679 720 // Wait for any pending parsing to complete. 680 721 dispatch_group_wait(m_isAppendingGroup.get(), DISPATCH_TIME_FOREVER); 681 } 682 683 void SourceBufferPrivateAVFObjC::resetParserState() 684 { 685 ALWAYS_LOG(LOGIDENTIFIER); 686 687 m_parser->resetParserState(); 688 } 689 690 void SourceBufferPrivateAVFObjC::destroyParser() 691 { 692 auto parser = this->parser(); 722 723 // Dispatch a task to complete all tasks that may have been queued by the 724 // appending group get to run first. 725 // We keep a strong reference to the parser so that it can't be destructed 726 // and can perform all required cleaning operations at the end of all operations. 727 callOnMainThread([weakThis = makeWeakPtr(*this), parser = m_parser, this]() { 728 parser->resetParserState(); 729 if (!weakThis) 730 return; 731 ASSERT(m_mediaSamples.isEmpty(), "All pending frames should have been processed"); 732 m_abortCalled = false; 733 }); 734 } 735 736 void SourceBufferPrivateAVFObjC::destroyStreamDataParser() 737 { 738 auto parser = this->streamDataParser(); 693 739 if (!parser) 694 740 return; … … 743 789 744 790 clearTrackBuffers(); 745 destroy Parser();791 destroyStreamDataParser(); 746 792 destroyRenderers(); 747 793 … … 841 887 } 842 888 843 AVStreamDataParser* SourceBufferPrivateAVFObjC:: parser() const889 AVStreamDataParser* SourceBufferPrivateAVFObjC::streamDataParser() const 844 890 { 845 891 if (is<SourceBufferParserAVFObjC>(m_parser.get())) 846 return downcast<SourceBufferParserAVFObjC>(m_parser.get()). parser();892 return downcast<SourceBufferParserAVFObjC>(m_parser.get()).streamDataParser(); 847 893 return nil; 848 894 } … … 909 955 return; 910 956 911 if (auto parser = this-> parser())957 if (auto parser = this->streamDataParser()) 912 958 [instanceSession->contentKeySession() addContentKeyRecipient:parser]; 913 959 if (m_hasSessionSemaphore) { -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.cpp
r278338 r279542 54 54 55 55 return nullptr; 56 } 57 58 static SourceBufferParser::CallOnClientThreadCallback callOnMainThreadCallback() 59 { 60 return [](Function<void()>&& function) { 61 callOnMainThread(WTFMove(function)); 62 }; 63 } 64 65 void SourceBufferParser::setCallOnClientThreadCallback(CallOnClientThreadCallback&& callback) 66 { 67 ASSERT(callback); 68 m_callOnClientThreadCallback = WTFMove(callback); 69 } 70 71 SourceBufferParser::SourceBufferParser() 72 : m_callOnClientThreadCallback(callOnMainThreadCallback()) 73 { 56 74 } 57 75 -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.h
r272039 r279542 83 83 }; 84 84 85 using CallOnClientThreadCallback = WTF::Function<void(WTF::Function<void()>&&)>; 86 void setCallOnClientThreadCallback(CallOnClientThreadCallback&&); 87 88 // appendData will be called on the SourceBufferPrivateAVFObjC data parser queue. 89 // Other methods will be called on the main thread, but only once appendData has returned. 85 90 virtual void appendData(Segment&&, CompletionHandler<void()>&& = [] { }, AppendFlags = AppendFlags::None) = 0; 86 91 virtual void flushPendingMediaData() = 0; … … 131 136 132 137 protected: 133 SourceBufferParser() = default;138 SourceBufferParser(); 134 139 140 CallOnClientThreadCallback m_callOnClientThreadCallback; 135 141 DidParseInitializationDataCallback m_didParseInitializationDataCallback; 136 142 DidEncounterErrorDuringParsingCallback m_didEncounterErrorDuringParsingCallback; -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp
r279492 r279542 593 593 } 594 594 595 static SourceBufferParserWebM::CallOnClientThreadCallback callOnMainThreadCallback()596 {597 return [](Function<void()>&& function) {598 callOnMainThread(WTFMove(function));599 };600 }601 602 595 SourceBufferParserWebM::SourceBufferParserWebM() 603 596 : m_reader(WTF::makeUniqueRef<StreamingVectorReader>()) 604 , m_callOnClientThreadCallback(callOnMainThreadCallback())605 597 { 606 598 if (isWebmParserAvailable()) … … 690 682 { 691 683 INFO_LOG_IF_POSSIBLE(LOGIDENTIFIER); 692 flushPendingAudioBuffers();693 684 if (m_parser) 694 685 m_parser->DidSeek(); 695 m_ state = State::None;696 m_ tracks.clear();686 m_reader->reset(); 687 m_state = m_initializationSegmentProcessed ? State::ReadingSegment : State::None; 697 688 m_initializationSegment = nullptr; 698 689 m_initializationSegmentEncountered = false; 699 690 m_currentBlock.reset(); 691 for (auto& track : m_tracks) 692 track->reset(); 700 693 } 701 694 … … 794 787 m_initializationSegmentEncountered = false; 795 788 m_initializationSegment = nullptr; 789 m_initializationSegmentProcessed = true; 796 790 797 791 if (!m_keyIds.isEmpty()) { … … 815 809 m_initializationSegmentEncountered = true; 816 810 m_initializationSegment = WTF::makeUniqueWithoutFastMallocCheck<InitializationSegment>(); 811 // TODO: Setting this to false here, will prevent adding a new media segment should a 812 // partial init segment be encountered after a call to sourceBuffer.abort(). 813 // It's probably fine as no-one in their right mind should send partial init segment only 814 // to immediately abort it. We do it this way mostly to avoid getting into a rabbit hole 815 // of ensuring that libwebm does something sane with rubbish input. 816 m_initializationSegmentProcessed = false; 817 817 818 818 return Status(Status::kOkCompleted); … … 1084 1084 #define PARSER_LOG_ERROR_IF_POSSIBLE(...) if (parser().loggerPtr()) parser().loggerPtr()->error(logChannel(), WTF::Logger::LogSiteIdentifier(logClassName(), __func__, parser().logIdentifier()), __VA_ARGS__) 1085 1085 1086 #if ENABLE(VP9) 1087 void SourceBufferParserWebM::VideoTrackData::reset() 1088 { 1089 m_currentBlockBuffer = nullptr; 1090 TrackData::reset(); 1091 } 1092 #endif 1093 1086 1094 webm::Status SourceBufferParserWebM::VideoTrackData::consumeFrameData(webm::Reader& reader, const FrameMetadata& metadata, uint64_t* bytesRemaining, const CMTime& presentationTime, int sampleCount) 1087 1095 { … … 1149 1157 createSampleBuffer(presentationTime, sampleCount, metadata); 1150 1158 1151 m_currentBlockBuffer = nullptr; 1152 m_partialBytesRead = 0; 1153 m_currentPacketSize = std::nullopt; 1159 reset(); 1154 1160 #else 1155 1161 UNUSED_PARAM(metadata); … … 1240 1246 UNUSED_PARAM(metadata); 1241 1247 #endif // ENABLE(VP9) 1248 } 1249 1250 void SourceBufferParserWebM::AudioTrackData::reset() 1251 { 1252 m_packetDescriptions.clear(); 1253 m_packetsData.clear(); 1254 m_currentPacketByteOffset = std::nullopt; 1255 TrackData::reset(); 1242 1256 } 1243 1257 … … 1402 1416 } 1403 1417 1404 void SourceBufferParserWebM::setCallOnClientThreadCallback(CallOnClientThreadCallback&& callback)1405 {1406 ASSERT(callback);1407 m_callOnClientThreadCallback = WTFMove(callback);1408 }1409 1410 1418 const MemoryCompactLookupOnlyRobinHoodHashSet<String>& SourceBufferParserWebM::supportedVideoCodecs() 1411 1419 { -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h
r279492 r279542 84 84 void setMinimumAudioSampleDuration(float); 85 85 86 using CallOnClientThreadCallback = WTF::Function<void(WTF::Function<void()>&&)>;87 void setCallOnClientThreadCallback(CallOnClientThreadCallback&&);88 89 86 void setLogger(const WTF::Logger&, const void* identifier) final; 90 87 … … 161 158 } 162 159 160 virtual void reset() 161 { 162 m_currentPacketSize = std::nullopt; 163 m_partialBytesRead = 0; 164 } 165 163 166 protected: 164 167 std::optional<size_t> m_currentPacketSize; … … 186 189 } 187 190 191 #if ENABLE(VP9) 192 void reset() final; 193 #endif 188 194 webm::Status consumeFrameData(webm::Reader&, const webm::FrameMetadata&, uint64_t*, const CMTime&, int) final; 189 195 190 196 private: 191 197 void createSampleBuffer(const CMTime&, int, const webm::FrameMetadata&); … … 212 218 213 219 webm::Status consumeFrameData(webm::Reader&, const webm::FrameMetadata&, uint64_t*, const CMTime&, int) final; 220 void reset() final; 214 221 void createSampleBuffer(std::optional<size_t> latestByteRangeOffset = std::nullopt); 215 222 … … 264 271 std::unique_ptr<webm::WebmParser> m_parser; 265 272 bool m_initializationSegmentEncountered { false }; 273 bool m_initializationSegmentProcessed { false }; 266 274 uint32_t m_timescale { 1000 }; 267 275 uint64_t m_currentTimecode { 0 }; … … 277 285 float m_minimumAudioSampleDuration { 2 }; 278 286 279 CallOnClientThreadCallback m_callOnClientThreadCallback;280 281 287 RefPtr<const WTF::Logger> m_logger; 282 288 const void* m_logIdentifier { nullptr };
Note: See TracChangeset
for help on using the changeset viewer.