Title: [277424] trunk/Source/WebCore
- Revision
- 277424
- Author
- [email protected]
- Date
- 2021-05-12 22:37:17 -0700 (Wed, 12 May 2021)
Log Message
[iPad] SourceBufferPrivateAVFObjC should not report an error to the web page when the video playback is interrupted
https://bugs.webkit.org/show_bug.cgi?id=225620
Reviewed by Jer Noble.
If `SourceBufferPrivateAVFObjC` reports an error to a web page when
`AVSampleBufferDisplayLayer` reports `AVErrorOperationInterrupted` (the playback
was interrupted), the web page will likely destroy the video player (and teardown
the video element). That behavior will lead to an empty picture-in-picture window
if the video was playing in picture-in-picture.
With this patch, `SourceBufferPrivateAVFObjC` will not report an error to the
web page in case of playback interruption. Instead, it takes a note that
the playback was interrupted, so that when we try to resume the playback later,
it will flush the `AVSampleBufferDisplayLayer` to recover the playback state.
In addition, we need to enqueue an IDR frame first before we enqueue more
samples after flushing the `AVSampleBufferDisplayLayer`. That is guaranteed
by `SourceBufferPrivate::reenqueSamples()`.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::playInternal):
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
(WebCore::MediaSourcePrivateAVFObjC::flushActiveSourceBuffersIfNeeded):
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(WebCore::SourceBufferPrivateAVFObjC::flushIfNeeded):
(WebCore::SourceBufferPrivateAVFObjC::layerDidReceiveError):
(WebCore::SourceBufferPrivateAVFObjC::isReadyForMoreSamples):
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (277423 => 277424)
--- trunk/Source/WebCore/ChangeLog 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/ChangeLog 2021-05-13 05:37:17 UTC (rev 277424)
@@ -1,3 +1,36 @@
+2021-05-12 Peng Liu <[email protected]>
+
+ [iPad] SourceBufferPrivateAVFObjC should not report an error to the web page when the video playback is interrupted
+ https://bugs.webkit.org/show_bug.cgi?id=225620
+
+ Reviewed by Jer Noble.
+
+ If `SourceBufferPrivateAVFObjC` reports an error to a web page when
+ `AVSampleBufferDisplayLayer` reports `AVErrorOperationInterrupted` (the playback
+ was interrupted), the web page will likely destroy the video player (and teardown
+ the video element). That behavior will lead to an empty picture-in-picture window
+ if the video was playing in picture-in-picture.
+
+ With this patch, `SourceBufferPrivateAVFObjC` will not report an error to the
+ web page in case of playback interruption. Instead, it takes a note that
+ the playback was interrupted, so that when we try to resume the playback later,
+ it will flush the `AVSampleBufferDisplayLayer` to recover the playback state.
+
+ In addition, we need to enqueue an IDR frame first before we enqueue more
+ samples after flushing the `AVSampleBufferDisplayLayer`. That is guaranteed
+ by `SourceBufferPrivate::reenqueSamples()`.
+
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::playInternal):
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
+ (WebCore::MediaSourcePrivateAVFObjC::flushActiveSourceBuffersIfNeeded):
+ * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+ * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+ (WebCore::SourceBufferPrivateAVFObjC::flushIfNeeded):
+ (WebCore::SourceBufferPrivateAVFObjC::layerDidReceiveError):
+ (WebCore::SourceBufferPrivateAVFObjC::isReadyForMoreSamples):
+
2021-05-12 Chris Dumez <[email protected]>
Notification.requestPermission() should return a Promise
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (277423 => 277424)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2021-05-13 05:37:17 UTC (rev 277424)
@@ -322,6 +322,9 @@
}
ALWAYS_LOG(LOGIDENTIFIER);
+#if PLATFORM(IOS_FAMILY)
+ m_mediaSourcePrivate->flushActiveSourceBuffersIfNeeded();
+#endif
m_playing = true;
if (shouldBePlaying())
[m_synchronizer setRate:m_rate];
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h (277423 => 277424)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h 2021-05-13 05:37:17 UTC (rev 277424)
@@ -93,6 +93,10 @@
void setVideoLayer(AVSampleBufferDisplayLayer*);
void setDecompressionSession(WebCoreDecompressionSession*);
+#if PLATFORM(IOS_FAMILY)
+ void flushActiveSourceBuffersIfNeeded();
+#endif
+
#if ENABLE(ENCRYPTED_MEDIA)
void cdmInstanceAttached(CDMInstance&);
void cdmInstanceDetached(CDMInstance&);
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm (277423 => 277424)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm 2021-05-13 05:37:17 UTC (rev 277424)
@@ -282,6 +282,14 @@
m_sourceBufferWithSelectedVideo->setDecompressionSession(decompressionSession);
}
+#if PLATFORM(IOS_FAMILY)
+void MediaSourcePrivateAVFObjC::flushActiveSourceBuffersIfNeeded()
+{
+ for (auto* sourceBuffer : m_activeSourceBuffers)
+ sourceBuffer->flushIfNeeded();
+}
+#endif
+
#if ENABLE(ENCRYPTED_MEDIA)
void MediaSourcePrivateAVFObjC::cdmInstanceAttached(CDMInstance& instance)
{
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (277423 => 277424)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h 2021-05-13 05:37:17 UTC (rev 277424)
@@ -109,6 +109,9 @@
bool waitingForKey() const { return m_waitingForKey; }
void flush();
+#if PLATFORM(IOS_FAMILY)
+ void flushIfNeeded();
+#endif
void registerForErrorNotifications(SourceBufferPrivateAVFObjCErrorClient*);
void unregisterForErrorNotifications(SourceBufferPrivateAVFObjCErrorClient*);
@@ -197,6 +200,9 @@
HashMap<uint64_t, RetainPtr<AVSampleBufferAudioRenderer>, DefaultHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> m_audioRenderers;
ALLOW_NEW_API_WITHOUT_GUARDS_END
RetainPtr<WebAVSampleBufferErrorListener> m_errorListener;
+#if PLATFORM(IOS_FAMILY)
+ bool m_displayLayerWasInterrupted { false };
+#endif
RetainPtr<NSError> m_hdcpError;
Box<BinarySemaphore> m_hasSessionSemaphore;
Box<Semaphore> m_abortSemaphore;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (277423 => 277424)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2021-05-13 05:36:57 UTC (rev 277423)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2021-05-13 05:37:17 UTC (rev 277424)
@@ -928,6 +928,27 @@
flushAudio(renderer.get());
}
+#if PLATFORM(IOS_FAMILY)
+void SourceBufferPrivateAVFObjC::flushIfNeeded()
+{
+ if (!m_displayLayerWasInterrupted)
+ return;
+
+ m_displayLayerWasInterrupted = false;
+ if (m_videoTracks.size())
+ flushVideo();
+
+ // We initiatively enqueue samples instead of waiting for the
+ // media data requests from m_decompressionSession and m_displayLayer.
+ // In addition, we need to enqueue a sync sample (IDR video frame) first.
+ if (m_decompressionSession)
+ m_decompressionSession->stopRequestingMediaData();
+ [m_displayLayer stopRequestingMediaData];
+
+ reenqueSamples(AtomString::number(m_enabledVideoTrackID));
+}
+#endif
+
void SourceBufferPrivateAVFObjC::registerForErrorNotifications(SourceBufferPrivateAVFObjCErrorClient* client)
{
ASSERT(!m_errorClients.contains(client));
@@ -944,6 +965,13 @@
{
ERROR_LOG(LOGIDENTIFIER, [[error description] UTF8String]);
+#if PLATFORM(IOS_FAMILY)
+ if ([layer status] == AVQueuedSampleBufferRenderingStatusFailed && [[error domain] isEqualToString:@"AVFoundationErrorDomain"] && [error code] == AVErrorOperationInterrupted) {
+ m_displayLayerWasInterrupted = true;
+ return;
+ }
+#endif
+
// FIXME(142246): Remove the following once <rdar://problem/20027434> is resolved.
bool anyIgnored = false;
for (auto& client : m_errorClients) {
@@ -1174,6 +1202,11 @@
{
auto trackID = parseIntegerAllowingTrailingJunk<uint64_t>(trackIDString).valueOr(0);
if (trackID == m_enabledVideoTrackID) {
+#if PLATFORM(IOS_FAMILY)
+ if (m_displayLayerWasInterrupted)
+ return false;
+#endif
+
if (m_decompressionSession)
return m_decompressionSession->isReadyForMoreMediaData();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes