Changeset 279904 in webkit
- Timestamp:
- Jul 13, 2021, 10:12:26 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r279901 r279904 1 2021-07-13 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 Jer Noble. 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-13 Eric Hutchison <ehutchison@apple.com> 2 20 -
trunk/LayoutTests/media/media-source/media-webm-opus-partial.html
r279622 r279904 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
r279622 r279904 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-wk2/TestExpectations
r279900 r279904 1251 1251 imported/w3c/web-platform-tests/mediacapture-record/MediaRecorder-error.html [ Pass Failure ] 1252 1252 1253 webkit.org/b/222500 fast/canvas/webgl/texImage2D-video-flipY-false.html [ Timeout ]1253 webkit.org/b/222500 fast/canvas/webgl/texImage2D-video-flipY-false.html [ Pass Timeout ] 1254 1254 1255 1255 webkit.org/b/222677 inspector/model/auditTestCase.html [ Pass Timeout ] -
trunk/LayoutTests/platform/mac/TestExpectations
r279894 r279904 1765 1765 # These tests require macOS Monterey. 1766 1766 [ Catalina Mojave BigSur ] media/media-source/media-webm-vorbis-partial.html [ Skip ] 1767 [ Catalina Mojave BigSur ] media/media-source/media-source-webm-vorbis-partial.html [ Skip ] 1767 1768 [ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial.html [ Skip ] 1769 [ Catalina Mojave BigSur ] media/media-source/media-webm-opus-partial-abort.html [ Skip ] 1768 1770 1769 1771 webkit.org/b/214422 imported/w3c/web-platform-tests/webaudio/the-audio-api/the-audiocontext-interface/suspend-after-construct.html [ Pass Failure ] … … 2160 2162 2161 2163 webkit.org/b/222573 media/media-fullscreen-pause-inline.html [ Pass Failure ] 2162 2163 webkit.org/b/222495 media/media-source/media-source-webm-vorbis-partial.html [ Failure ]2164 2164 2165 2165 webkit.org/b/222692 inspector/page/empty-or-missing-resources.html [ Pass Timeout ] -
trunk/Source/WebCore/ChangeLog
r279886 r279904 1 2021-07-13 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 Jer Noble. 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 and drop all demuxed samples. 28 The SourceBufferParserAVFObjC could already properly deal with discontinuity unlike 29 SourceBufferParserWebM. 30 To ensure that buffers sent after the call to abort() are only ever processed once 31 the pending ones have been parsed, and in order to avoid having blocking calls 32 we play with the order in which tasks are scheduled. 33 34 Fly-by fixes: 35 - The SourceBufferParser handle two type of parser: SourceBufferParser and the 36 platform specific AVStreamDataParser. Rename the accessor method to more clearly 37 differentate which parser we are dealing with. 38 - The SourceBufferParserWebM and SourceBufferPrivateAVFObjC used different task dispatching 39 mechanisms. We make them both share the same one now found in the base class. 40 - If SourceBufferPrivateAVFObjC::m_hasPendingAppendCompletedCallback had been set prior an 41 abort() it wouldn't have been reset, causing the need for a new init segment. 42 - If abort() had been called while samples were pending, the source buffer content was 43 undefined if timestamp offset or append windows start/end were changed immediately after. 44 - When an error occurs during the Segment Parser Loop, we should abort and run the append 45 error algorithm. We instead fired an error event for each sample found in the media segment. 46 In a debug built it was have asserted. We can't actually abort, so instead we ignore all 47 further samples once an error is encountered. 48 49 Tests: media/media-source/media-mp4-h264-partial-abort.html 50 media/media-source/media-webm-opus-partial-abort.html 51 52 * platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm: 53 (WebCore::CDMSessionAVContentKeySession::~CDMSessionAVContentKeySession): rename method. 54 * platform/graphics/avfoundation/objc/CDMSessionAVStreamSession.mm: 55 (WebCore::CDMSessionAVStreamSession::~CDMSessionAVStreamSession): rename method. 56 (WebCore::CDMSessionAVStreamSession::update): rename method. 57 * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm: rename method. 58 (WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer): rename method. 59 (WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer): rename method. 60 * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h: rename method, remove 61 now unused member. 62 * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm: 63 (WebCore::SourceBufferPrivateAVFObjC::removeCodedFrames): Postpone call to ensure 64 we are running the remove frame algorithm once all pending frames have been processed. 65 (WebCore::SourceBufferParserAVFObjC::resetParserState): Remove use of m_discardSamplesUntilNextInitializationSegment. 66 (WebCore::SourceBufferParserAVFObjC::didParseStreamDataAsAsset): Change to base dispatch method. 67 (WebCore::SourceBufferParserAVFObjC::didFailToParseStreamDataWithError): Change to base dispatch method. 68 (WebCore::SourceBufferParserAVFObjC::didProvideMediaDataForTrackID): Change to base dispatch method. 69 * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h: Rename methods. Remove no longer used 70 members. 71 * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm: 72 (WebCore::SourceBufferPrivateAVFObjC::~SourceBufferPrivateAVFObjC): 73 (WebCore::SourceBufferPrivateAVFObjC::didParseInitializationData): No longer use a Cancellable task 74 as we never cancel it anymore. 75 (WebCore::SourceBufferPrivateAVFObjC::append): re-schedule the append task immediately to ensure 76 that processed packets flushed on the parser queue during abort are handled in the right order on 77 the main thread. 78 (WebCore::SourceBufferPrivateAVFObjC::appendCompleted): Check that abort wasn't called since append started 79 to ensure that no updateend event is incorrectly fired twice. 80 (WebCore::SourceBufferPrivateAVFObjC::abort): Abort is now a no-op that only set the m_abortCalled member. 81 (WebCore::SourceBufferPrivateAVFObjC::resetParserState): Change the order of operations so that the 82 SourceBufferParser is only reset after it has finished processing its data. 83 (WebCore::SourceBufferPrivateAVFObjC::destroyStreamDataParser): Use rename method. 84 (WebCore::SourceBufferPrivateAVFObjC::removedFromMediaSource): Use rename method. 85 (WebCore::SourceBufferPrivateAVFObjC::streamDataParser const): Renamed method from "parser" 86 (WebCore::SourceBufferPrivateAVFObjC::attemptToDecrypt): Use renamed method. 87 * platform/graphics/cocoa/SourceBufferParser.cpp: 88 (WebCore::callOnMainThreadCallback): Move dispatch method from SourceBufferParserWebM 89 (WebCore::SourceBufferParser::setCallOnClientThreadCallback): 90 (WebCore::SourceBufferParser::SourceBufferParser): 91 * platform/graphics/cocoa/SourceBufferParser.h: 92 * platform/graphics/cocoa/SourceBufferParserWebM.cpp: 93 (WebCore::SourceBufferParserWebM::SourceBufferParserWebM): 94 (WebCore::SourceBufferParserWebM::resetParserState): Don't clear the data set by parsing 95 the previous init segment. Set the parsing state to waiting for a new segment if an 96 init segment has been fully parsed. 97 (WebCore::SourceBufferParserWebM::OnElementEnd): 98 (WebCore::SourceBufferParserWebM::OnEbml): 99 (WebCore::SourceBufferParserWebM::VideoTrackData::reset): 100 (WebCore::SourceBufferParserWebM::VideoTrackData::consumeFrameData): 101 (WebCore::SourceBufferParserWebM::AudioTrackData::reset): 102 * platform/graphics/cocoa/SourceBufferParserWebM.h: 103 1 104 2021-07-13 Alex Christensen <achristensen@webkit.org> 2 105 -
trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
r278728 r279904 171 171 172 172 if (m_client) { 173 m_client->sourceBufferPrivateAppendComplete(parsingSucceeded ? SourceBufferPrivateClient::AppendResult::AppendSucceeded : SourceBufferPrivateClient::AppendResult::ParsingFailed); 173 if (!m_didReceiveSampleErrored) 174 m_client->sourceBufferPrivateAppendComplete(parsingSucceeded ? SourceBufferPrivateClient::AppendResult::AppendSucceeded : SourceBufferPrivateClient::AppendResult::ParsingFailed); 174 175 m_client->sourceBufferPrivateReportExtraMemoryCost(totalTrackBufferSizeInBytes()); 175 176 } … … 830 831 void SourceBufferPrivate::didReceiveSample(Ref<MediaSample>&& originalSample) 831 832 { 832 if (!m_isAttached )833 if (!m_isAttached || m_didReceiveSampleErrored) 833 834 return; 834 835 … … 844 845 if ((!m_receivedFirstInitializationSegment || m_pendingInitializationSegmentForChangeType) && m_client) { 845 846 m_client->sourceBufferPrivateAppendError(true); 847 m_didReceiveSampleErrored = true; 846 848 return; 847 849 } -
trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h
r278603 r279904 192 192 bool m_receivedFirstInitializationSegment { false }; 193 193 bool m_pendingInitializationSegmentForChangeType { false }; 194 bool m_didReceiveSampleErrored { false }; 194 195 195 196 MediaTime m_timestampOffset; -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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*); … … 173 173 void didBecomeReadyForMoreSamples(uint64_t trackID); 174 174 void appendCompleted(); 175 void destroy Parser();175 void destroyStreamDataParser(); 176 176 void destroyRenderers(); 177 177 void clearTracks(); … … 191 191 192 192 Ref<SourceBufferParser> m_parser; 193 bool m_ initializationSegmentIsHandled{ false };193 bool m_processingInitializationSegment { false }; 194 194 bool m_hasPendingAppendCompletedCallback { false }; 195 195 Vector<std::pair<uint64_t, Ref<MediaSample>>> m_mediaSamples; 196 TaskCancellationGroup m_mediaSampleTaskCancellationGroup;197 196 198 197 RetainPtr<AVSampleBufferDisplayLayer> m_displayLayer; … … 228 227 uint64_t m_protectedTrackID { notFound }; 229 228 uint64_t m_mapID; 229 uint32_t m_abortCalled { 0 }; 230 230 231 231 #if !RELEASE_LOG_DISABLED -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
r279622 r279904 323 323 324 324 sourceBufferMap().add(m_mapID, makeWeakPtr(*this)); 325 326 m_parser->setDidParseInitializationDataCallback([weakThis = makeWeakPtr(this)] (InitializationSegment&& segment) mutable {327 ASSERT(isMainThread());328 if (weakThis)329 weakThis->didParseInitializationData(WTFMove(segment));330 });331 332 m_parser->setDidEncounterErrorDuringParsingCallback([weakThis = makeWeakPtr(this)] (int32_t errorCode) mutable {333 ASSERT(isMainThread());334 if (weakThis)335 weakThis->didEncounterErrorDuringParsing(errorCode);336 });337 338 m_parser->setDidProvideMediaDataCallback([weakThis = makeWeakPtr(this)] (Ref<MediaSample>&& sample, uint64_t trackId, const String& mediaType) mutable {339 ASSERT(isMainThread());340 if (weakThis)341 weakThis->didProvideMediaDataForTrackId(WTFMove(sample), trackId, mediaType);342 });343 325 } 344 326 … … 349 331 ASSERT(!m_client); 350 332 sourceBufferMap().remove(m_mapID); 351 destroy Parser();333 destroyStreamDataParser(); 352 334 destroyRenderers(); 353 335 clearTracks(); … … 356 338 PAL::CMNotificationCenterRemoveListener(PAL::CMNotificationCenterGetDefaultLocalCenter(), this, bufferWasConsumedCallback, PAL::kCMSampleBufferConsumerNotification_BufferConsumed, nullptr); 357 339 358 if (m_hasSessionSemaphore) 359 m_hasSessionSemaphore->signal(); 360 361 m_mediaSampleTaskCancellationGroup.cancel(); 340 abort(); 341 resetParserState(); 362 342 } 363 343 … … 403 383 player->characteristicsChanged(); 404 384 405 m_ initializationSegmentIsHandled = false;406 didReceiveInitializationSegment(WTFMove(segment), [this, weakThis = makeWeakPtr(*this) ]() mutable{385 m_processingInitializationSegment = true; 386 didReceiveInitializationSegment(WTFMove(segment), [this, weakThis = makeWeakPtr(*this), abortCalled = m_abortCalled]() { 407 387 ASSERT(isMainThread()); 408 if (!weakThis )388 if (!weakThis || abortCalled != weakThis->m_abortCalled) 409 389 return; 390 391 m_processingInitializationSegment = false; 410 392 411 393 if (auto player = this->player()) 412 394 player->characteristicsChanged(); 413 395 414 if (m_mediaSamples.isEmpty()) { 415 m_initializationSegmentIsHandled = true; 416 ALWAYS_LOG(LOGIDENTIFIER, "initialization segment is handled"); 417 return; 396 auto mediaSamples = std::exchange(m_mediaSamples, { }); 397 for (auto& trackIdMediaSamplePair : mediaSamples) { 398 auto trackId = trackIdMediaSamplePair.first; 399 auto& mediaSample = trackIdMediaSamplePair.second; 400 if (trackId == m_enabledVideoTrackID || m_audioRenderers.contains(trackId)) { 401 DEBUG_LOG(LOGIDENTIFIER, mediaSample.get()); 402 didReceiveSample(WTFMove(mediaSample)); 403 } 418 404 } 419 405 420 callOnMainThread(CancellableTask(m_mediaSampleTaskCancellationGroup, [this, weakThis = WTFMove(weakThis)] { 421 if (!weakThis) 422 return; 423 424 auto mediaSamples = std::exchange(m_mediaSamples, { }); 425 for (auto& trackIdMediaSamplePair : mediaSamples) { 426 auto trackId = trackIdMediaSamplePair.first; 427 auto& mediaSample = trackIdMediaSamplePair.second; 428 if (trackId == m_enabledVideoTrackID || m_audioRenderers.contains(trackId)) { 429 DEBUG_LOG(LOGIDENTIFIER, mediaSample.get()); 430 didReceiveSample(WTFMove(mediaSample)); 431 } 432 } 433 434 m_initializationSegmentIsHandled = true; 435 ALWAYS_LOG(LOGIDENTIFIER, "initialization segment is handled"); 436 437 if (m_hasPendingAppendCompletedCallback) { 438 m_hasPendingAppendCompletedCallback = false; 439 appendCompleted(); 440 } 441 })); 406 ALWAYS_LOG(LOGIDENTIFIER, "initialization segment was processed"); 407 408 if (m_hasPendingAppendCompletedCallback) { 409 m_hasPendingAppendCompletedCallback = false; 410 appendCompleted(); 411 } 442 412 }); 443 413 } … … 456 426 { 457 427 UNUSED_PARAM(mediaType); 458 if (!m_initializationSegmentIsHandled) { 428 429 if (m_processingInitializationSegment) { 459 430 DEBUG_LOG(LOGIDENTIFIER, mediaSample.get()); 460 431 m_mediaSamples.append(std::make_pair(trackId, WTFMove(mediaSample))); … … 482 453 m_protectedTrackID = trackID; 483 454 484 auto parser = this-> parser();455 auto parser = this->streamDataParser(); 485 456 if (!parser) 486 457 return; … … 515 486 m_mediaSource->sourceBufferKeyNeeded(this, m_initData.get()); 516 487 if (auto session = player->cdmSession()) { 517 if (auto parser = this-> parser())488 if (auto parser = this->streamDataParser()) 518 489 session->addParser(parser); 519 490 hasSessionSemaphore->signal(); … … 534 505 if (m_cdmInstance) { 535 506 if (auto instanceSession = m_cdmInstance->sessionForKeyIDs(keyIDs.value())) { 536 if (auto parser = this-> parser())507 if (auto parser = this->streamDataParser()) 537 508 [instanceSession->contentKeySession() addContentKeyRecipient:parser]; 538 509 if (m_hasSessionSemaphore) { … … 577 548 m_client->sourceBufferPrivateReportExtraMemoryCost(totalTrackBufferSizeInBytes()); 578 549 550 m_parser->setDidParseInitializationDataCallback([weakThis = makeWeakPtr(this), abortCalled = m_abortCalled] (InitializationSegment&& segment) { 551 ASSERT(isMainThread()); 552 if (!weakThis || abortCalled != weakThis->m_abortCalled) 553 return; 554 weakThis->didParseInitializationData(WTFMove(segment)); 555 }); 556 557 m_parser->setDidEncounterErrorDuringParsingCallback([weakThis = makeWeakPtr(this), abortCalled = m_abortCalled] (int32_t errorCode) { 558 ASSERT(isMainThread()); 559 if (!weakThis || abortCalled != weakThis->m_abortCalled) 560 return; 561 weakThis->didEncounterErrorDuringParsing(errorCode); 562 }); 563 564 m_parser->setDidProvideMediaDataCallback([weakThis = makeWeakPtr(this), abortCalled = m_abortCalled] (Ref<MediaSample>&& sample, uint64_t trackId, const String& mediaType) { 565 ASSERT(isMainThread()); 566 if (!weakThis || abortCalled != weakThis->m_abortCalled) 567 return; 568 weakThis->didProvideMediaDataForTrackId(WTFMove(sample), trackId, mediaType); 569 }); 570 579 571 m_abortSemaphore = Box<Semaphore>::create(0); 580 m_parser->setWillProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore ] (uint64_t trackID) mutable {572 m_parser->setWillProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore, abortCalled = m_abortCalled] (uint64_t trackID) mutable { 581 573 // We must call synchronously to the main thread, as the AVStreamSession must be associated 582 574 // with the streamDataParser before the delegate method returns. 583 575 Box<BinarySemaphore> respondedSemaphore = Box<BinarySemaphore>::create(); 584 callOnMainThread([weakThis = WTFMove(weakThis), trackID, respondedSemaphore]() {585 if (weakThis )576 callOnMainThread([weakThis = WTFMove(weakThis), abortCalled, trackID, respondedSemaphore]() { 577 if (weakThis && abortCalled == weakThis->m_abortCalled) 586 578 weakThis->willProvideContentKeyRequestInitializationDataForTrackID(trackID); 587 579 respondedSemaphore->signal(); … … 599 591 }); 600 592 601 m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore] (Ref<Uint8Array>&& initData, uint64_t trackID) mutable { 593 m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = makeWeakPtr(this), abortSemaphore = m_abortSemaphore, abortCalled = m_abortCalled](Ref<Uint8Array>&& initData, uint64_t trackID) mutable { 594 // Called on the data parser queue. 602 595 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); 596 callOnMainThread([weakThis = WTFMove(weakThis), abortCalled, initData = WTFMove(initData), trackID, hasSessionSemaphore] () mutable { 597 if (!weakThis || abortCalled != weakThis->m_abortCalled) 598 return; 599 weakThis->didProvideContentKeyRequestInitializationDataForTrackID(WTFMove(initData), trackID, hasSessionSemaphore); 606 600 }); 607 601 … … 620 614 dispatch_group_enter(m_isAppendingGroup.get()); 621 615 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) ] {625 if (!weakThis )616 dispatch_async(globalDataParserQueue(), [data = WTFMove(data), weakThis = m_appendWeakFactory.createWeakPtr(*this), parser = m_parser, isAppendingGroup = m_isAppendingGroup, abortCalled = m_abortCalled]() mutable { 617 parser->appendData(WTFMove(data), [weakThis = WTFMove(weakThis), abortCalled]() mutable { 618 callOnMainThread([weakThis = WTFMove(weakThis), abortCalled] { 619 if (!weakThis || abortCalled != weakThis->m_abortCalled) 626 620 return; 627 621 628 if ( !weakThis->m_mediaSamples.isEmpty()) {622 if (weakThis->m_processingInitializationSegment) { 629 623 weakThis->m_hasPendingAppendCompletedCallback = true; 630 624 return; … … 661 655 ALWAYS_LOG(LOGIDENTIFIER); 662 656 663 // The parsing queue may be blocked waiting for the main thread to provide it a AVStreamSession. We657 // The parsing queue may be blocked waiting for the main thread to provide it an AVStreamSession. We 664 658 // were asked to abort, and that cancels all outstanding append operations. Without cancelling this 665 659 // semaphore, the m_isAppendingGroup wait operation will deadlock. … … 673 667 } 674 668 669 m_abortCalled++; 670 } 671 672 void SourceBufferPrivateAVFObjC::resetParserState() 673 { 674 ALWAYS_LOG(LOGIDENTIFIER); 675 676 dispatch_group_wait(m_isAppendingGroup.get(), DISPATCH_TIME_FOREVER); 677 m_mediaSamples.clear(); 678 m_hasPendingAppendCompletedCallback = false; 679 m_processingInitializationSegment = false; 675 680 m_parser->resetParserState(); 676 m_mediaSamples.clear(); 677 m_initializationSegmentIsHandled = false; 678 m_mediaSampleTaskCancellationGroup.cancel(); 679 680 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(); 681 } 682 683 void SourceBufferPrivateAVFObjC::destroyStreamDataParser() 684 { 685 auto parser = this->streamDataParser(); 693 686 if (!parser) 694 687 return; … … 743 736 744 737 clearTrackBuffers(); 745 destroy Parser();738 destroyStreamDataParser(); 746 739 destroyRenderers(); 747 740 … … 841 834 } 842 835 843 AVStreamDataParser* SourceBufferPrivateAVFObjC:: parser() const836 AVStreamDataParser* SourceBufferPrivateAVFObjC::streamDataParser() const 844 837 { 845 838 if (is<SourceBufferParserAVFObjC>(m_parser.get())) 846 return downcast<SourceBufferParserAVFObjC>(m_parser.get()). parser();839 return downcast<SourceBufferParserAVFObjC>(m_parser.get()).streamDataParser(); 847 840 return nil; 848 841 } … … 909 902 return; 910 903 911 if (auto parser = this-> parser())904 if (auto parser = this->streamDataParser()) 912 905 [instanceSession->contentKeySession() addContentKeyRecipient:parser]; 913 906 if (m_hasSessionSemaphore) { … … 1165 1158 } 1166 1159 1167 callOnMainThread([weakThis = WTFMove(weakThis)] () mutable{1160 callOnMainThread([weakThis = WTFMove(weakThis)] () { 1168 1161 if (!weakThis) 1169 1162 return; -
trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.cpp
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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
r279622 r279904 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.