Title: [258846] trunk/Source/WebCore
Revision
258846
Author
jer.no...@apple.com
Date
2020-03-23 08:38:54 -0700 (Mon, 23 Mar 2020)

Log Message

[MSE] Handle the case where AVStreamDataParser packages sync and non-sync samples together in a CMSampleBufferRef.
https://bugs.webkit.org/show_bug.cgi?id=209365
<rdar://problem/60625209>

Reviewed by Eric Carlson.

AVStreamDataParser will package together muliple samples into a single CMSampleBufferRef for efficiency's sake. When
this occurs, it may include sync and non-sync samples together into the same CMSampleBufferRef, which is problematic
as we consider a CMSampleBufferRef to be "sync" only when every sample inside the buffer is also sync.

To handle this scenario, when receiving a CMSampleBufferRef from AVStreamDataParser, first check whether that buffer
is "homogeneous", meaning every sample within the buffer has the same effective MediaSample flags. Then, if the buffer
is not homogenous, break the buffer into muliple homogenious CMSampleBufferRefs. Then, each of those resulting buffers
is passed up to SourceBuffer as a MediaSample individually.

* platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm:
(WebCore::isCMSampleBufferAttachmentRandomAccess):
(WebCore::isCMSampleBufferRandomAccess):
(WebCore::isCMSampleBufferAttachmentNonDisplaying):
(WebCore::isCMSampleBufferNonDisplaying):
(WebCore::MediaSampleAVFObjC::flags const):
(WebCore::MediaSampleAVFObjC::isHomogeneous const):
(WebCore::MediaSampleAVFObjC::divideIntoHomogeneousSamples):
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(WebCore::SourceBufferPrivateAVFObjC::processCodedFrame):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (258845 => 258846)


--- trunk/Source/WebCore/ChangeLog	2020-03-23 15:35:42 UTC (rev 258845)
+++ trunk/Source/WebCore/ChangeLog	2020-03-23 15:38:54 UTC (rev 258846)
@@ -1,3 +1,32 @@
+2020-03-23  Jer Noble  <jer.no...@apple.com>
+
+        [MSE] Handle the case where AVStreamDataParser packages sync and non-sync samples together in a CMSampleBufferRef.
+        https://bugs.webkit.org/show_bug.cgi?id=209365
+        <rdar://problem/60625209>
+
+        Reviewed by Eric Carlson.
+
+        AVStreamDataParser will package together muliple samples into a single CMSampleBufferRef for efficiency's sake. When
+        this occurs, it may include sync and non-sync samples together into the same CMSampleBufferRef, which is problematic
+        as we consider a CMSampleBufferRef to be "sync" only when every sample inside the buffer is also sync.
+
+        To handle this scenario, when receiving a CMSampleBufferRef from AVStreamDataParser, first check whether that buffer
+        is "homogeneous", meaning every sample within the buffer has the same effective MediaSample flags. Then, if the buffer
+        is not homogenous, break the buffer into muliple homogenious CMSampleBufferRefs. Then, each of those resulting buffers
+        is passed up to SourceBuffer as a MediaSample individually.
+
+        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm:
+        (WebCore::isCMSampleBufferAttachmentRandomAccess):
+        (WebCore::isCMSampleBufferRandomAccess):
+        (WebCore::isCMSampleBufferAttachmentNonDisplaying):
+        (WebCore::isCMSampleBufferNonDisplaying):
+        (WebCore::MediaSampleAVFObjC::flags const):
+        (WebCore::MediaSampleAVFObjC::isHomogeneous const):
+        (WebCore::MediaSampleAVFObjC::divideIntoHomogeneousSamples):
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (WebCore::SourceBufferPrivateAVFObjC::processCodedFrame):
+
 2020-03-23  Alicia Boya GarcĂ­a  <ab...@igalia.com>
 
         [MSE][GStreamer] Clean and explain first sample PTS hack

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h (258845 => 258846)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h	2020-03-23 15:35:42 UTC (rev 258845)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h	2020-03-23 15:38:54 UTC (rev 258846)
@@ -68,6 +68,9 @@
 
     CMSampleBufferRef sampleBuffer() const { return m_sample.get(); }
 
+    bool isHomogeneous() const;
+    Vector<Ref<MediaSampleAVFObjC>> divideIntoHomogeneousSamples();
+
 protected:
     MediaSampleAVFObjC(RetainPtr<CMSampleBufferRef>&& sample)
         : m_sample(WTFMove(sample))

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm (258845 => 258846)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm	2020-03-23 15:35:42 UTC (rev 258845)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm	2020-03-23 15:38:54 UTC (rev 258846)
@@ -115,6 +115,11 @@
     return CVPixelBufferGetPixelFormatType(pixelBuffer);
 }
 
+static bool isCMSampleBufferAttachmentRandomAccess(CFDictionaryRef attachmentDict)
+{
+    return !CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_NotSync);
+}
+
 static bool isCMSampleBufferRandomAccess(CMSampleBufferRef sample)
 {
     CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sample, false);
@@ -122,13 +127,17 @@
         return true;
     
     for (CFIndex i = 0, count = CFArrayGetCount(attachments); i < count; ++i) {
-        CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i));
-        if (CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_NotSync))
+        if (!isCMSampleBufferAttachmentRandomAccess(checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i))))
             return false;
     }
     return true;
 }
 
+static bool isCMSampleBufferAttachmentNonDisplaying(CFDictionaryRef attachmentDict)
+{
+    return CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_DoNotDisplay);
+}
+
 static bool isCMSampleBufferNonDisplaying(CMSampleBufferRef sample)
 {
     CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sample, false);
@@ -136,8 +145,7 @@
         return false;
     
     for (CFIndex i = 0; i < CFArrayGetCount(attachments); ++i) {
-        CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i));
-        if (CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_DoNotDisplay))
+        if (isCMSampleBufferAttachmentNonDisplaying(checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i))))
             return true;
     }
 
@@ -147,13 +155,13 @@
 MediaSample::SampleFlags MediaSampleAVFObjC::flags() const
 {
     int returnValue = MediaSample::None;
-    
+
     if (isCMSampleBufferRandomAccess(m_sample.get()))
         returnValue |= MediaSample::IsSync;
 
     if (isCMSampleBufferNonDisplaying(m_sample.get()))
         returnValue |= MediaSample::IsNonDisplaying;
-    
+
     return SampleFlags(returnValue);
 }
 
@@ -316,4 +324,74 @@
     }
 }
 
+bool MediaSampleAVFObjC::isHomogeneous() const
+{
+    CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(m_sample.get(), true);
+    if (!attachmentsArray)
+        return true;
+
+    auto count = CFArrayGetCount(attachmentsArray);
+    if (count <= 1)
+        return true;
+
+    CFDictionaryRef firstAttachment = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, 0));
+    bool isSync = isCMSampleBufferAttachmentRandomAccess(firstAttachment);
+    bool isNonDisplaying = isCMSampleBufferAttachmentNonDisplaying(firstAttachment);
+
+    for (CFIndex i = 1; i < count; ++i) {
+        auto attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, i));
+        if (isSync != isCMSampleBufferAttachmentRandomAccess(attachmentDict))
+            return false;
+
+        if (isNonDisplaying != isCMSampleBufferAttachmentNonDisplaying(attachmentDict))
+            return false;
+    };
+
+    return true;
 }
+
+Vector<Ref<MediaSampleAVFObjC>> MediaSampleAVFObjC::divideIntoHomogeneousSamples()
+{
+    using SampleVector = Vector<Ref<MediaSampleAVFObjC>>;
+
+    CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(m_sample.get(), true);
+    if (!attachmentsArray)
+        return SampleVector::from(makeRef(*this));
+
+    auto count = CFArrayGetCount(attachmentsArray);
+    if (count <= 1)
+        return SampleVector::from(makeRef(*this));
+
+    CFDictionaryRef firstAttachment = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, 0));
+    bool isSync = isCMSampleBufferAttachmentRandomAccess(firstAttachment);
+    bool isNonDisplaying = isCMSampleBufferAttachmentNonDisplaying(firstAttachment);
+    Vector<CFRange> ranges;
+    CFIndex currentRangeStart = 0;
+    CFIndex currentRangeLength = 1;
+
+    for (CFIndex i = 1; i < count; ++i, ++currentRangeLength) {
+        CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, i));
+        if (isSync == isCMSampleBufferAttachmentRandomAccess(attachmentDict) && isNonDisplaying == isCMSampleBufferAttachmentNonDisplaying(attachmentDict))
+            continue;
+
+        ranges.append(CFRangeMake(currentRangeStart, currentRangeLength));
+        currentRangeStart = i;
+        currentRangeLength = 0;
+    }
+    ranges.append(CFRangeMake(currentRangeStart, currentRangeLength));
+
+    if (ranges.size() == 1)
+        return SampleVector::from(makeRef(*this));
+
+    SampleVector samples;
+    samples.reserveInitialCapacity(ranges.size());
+    for (auto& range : ranges) {
+        CMSampleBufferRef rawSample = nullptr;
+        if (CMSampleBufferCopySampleBufferForRange(kCFAllocatorDefault, m_sample.get(), range, &rawSample) != noErr || !rawSample)
+            return { };
+        samples.uncheckedAppend(MediaSampleAVFObjC::create(adoptCF(rawSample).get(), m_id));
+    }
+    return samples;
+}
+
+}

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (258845 => 258846)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2020-03-23 15:35:42 UTC (rev 258845)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2020-03-23 15:38:54 UTC (rev 258846)
@@ -598,12 +598,23 @@
     if (m_discardSamplesUntilNextInitializationSegment)
         return false;
 
-    if (m_client) {
-        Ref<MediaSample> mediaSample = MediaSampleAVFObjC::create(sampleBuffer, trackID);
-        DEBUG_LOG(LOGIDENTIFIER, mediaSample.get());
+    if (!m_client)
+        return true;
+
+    auto mediaSample = MediaSampleAVFObjC::create(sampleBuffer, trackID);
+
+    if (mediaSample->isHomogeneous()) {
+        DEBUG_LOG(LOGIDENTIFIER, mediaSample->toJSONString());
         m_client->sourceBufferPrivateDidReceiveSample(mediaSample);
+        return true;
     }
 
+    auto mediaSamples = mediaSample->divideIntoHomogeneousSamples();
+    for (auto& sample : mediaSamples) {
+        DEBUG_LOG(LOGIDENTIFIER, sample->toJSONString());
+        m_client->sourceBufferPrivateDidReceiveSample(sample);
+    }
+
     return true;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to