Changeset 258846 in webkit


Ignore:
Timestamp:
Mar 23, 2020 8:38:54 AM (4 years ago)
Author:
jer.noble@apple.com
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):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r258844 r258846  
     12020-03-23  Jer Noble  <jer.noble@apple.com>
     2
     3        [MSE] Handle the case where AVStreamDataParser packages sync and non-sync samples together in a CMSampleBufferRef.
     4        https://bugs.webkit.org/show_bug.cgi?id=209365
     5        <rdar://problem/60625209>
     6
     7        Reviewed by Eric Carlson.
     8
     9        AVStreamDataParser will package together muliple samples into a single CMSampleBufferRef for efficiency's sake. When
     10        this occurs, it may include sync and non-sync samples together into the same CMSampleBufferRef, which is problematic
     11        as we consider a CMSampleBufferRef to be "sync" only when every sample inside the buffer is also sync.
     12
     13        To handle this scenario, when receiving a CMSampleBufferRef from AVStreamDataParser, first check whether that buffer
     14        is "homogeneous", meaning every sample within the buffer has the same effective MediaSample flags. Then, if the buffer
     15        is not homogenous, break the buffer into muliple homogenious CMSampleBufferRefs. Then, each of those resulting buffers
     16        is passed up to SourceBuffer as a MediaSample individually.
     17
     18        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h:
     19        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm:
     20        (WebCore::isCMSampleBufferAttachmentRandomAccess):
     21        (WebCore::isCMSampleBufferRandomAccess):
     22        (WebCore::isCMSampleBufferAttachmentNonDisplaying):
     23        (WebCore::isCMSampleBufferNonDisplaying):
     24        (WebCore::MediaSampleAVFObjC::flags const):
     25        (WebCore::MediaSampleAVFObjC::isHomogeneous const):
     26        (WebCore::MediaSampleAVFObjC::divideIntoHomogeneousSamples):
     27        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
     28        (WebCore::SourceBufferPrivateAVFObjC::processCodedFrame):
     29
    1302020-03-23  Alicia Boya García  <aboya@igalia.com>
    231
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h

    r258807 r258846  
    6969    CMSampleBufferRef sampleBuffer() const { return m_sample.get(); }
    7070
     71    bool isHomogeneous() const;
     72    Vector<Ref<MediaSampleAVFObjC>> divideIntoHomogeneousSamples();
     73
    7174protected:
    7275    MediaSampleAVFObjC(RetainPtr<CMSampleBufferRef>&& sample)
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.mm

    r258807 r258846  
    116116}
    117117
     118static bool isCMSampleBufferAttachmentRandomAccess(CFDictionaryRef attachmentDict)
     119{
     120    return !CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_NotSync);
     121}
     122
    118123static bool isCMSampleBufferRandomAccess(CMSampleBufferRef sample)
    119124{
     
    123128   
    124129    for (CFIndex i = 0, count = CFArrayGetCount(attachments); i < count; ++i) {
    125         CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i));
    126         if (CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_NotSync))
     130        if (!isCMSampleBufferAttachmentRandomAccess(checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i))))
    127131            return false;
    128132    }
    129133    return true;
     134}
     135
     136static bool isCMSampleBufferAttachmentNonDisplaying(CFDictionaryRef attachmentDict)
     137{
     138    return CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_DoNotDisplay);
    130139}
    131140
     
    137146   
    138147    for (CFIndex i = 0; i < CFArrayGetCount(attachments); ++i) {
    139         CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i));
    140         if (CFDictionaryContainsKey(attachmentDict, kCMSampleAttachmentKey_DoNotDisplay))
     148        if (isCMSampleBufferAttachmentNonDisplaying(checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, i))))
    141149            return true;
    142150    }
     
    148156{
    149157    int returnValue = MediaSample::None;
    150    
     158
    151159    if (isCMSampleBufferRandomAccess(m_sample.get()))
    152160        returnValue |= MediaSample::IsSync;
     
    154162    if (isCMSampleBufferNonDisplaying(m_sample.get()))
    155163        returnValue |= MediaSample::IsNonDisplaying;
    156    
     164
    157165    return SampleFlags(returnValue);
    158166}
     
    317325}
    318326
    319 }
     327bool MediaSampleAVFObjC::isHomogeneous() const
     328{
     329    CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(m_sample.get(), true);
     330    if (!attachmentsArray)
     331        return true;
     332
     333    auto count = CFArrayGetCount(attachmentsArray);
     334    if (count <= 1)
     335        return true;
     336
     337    CFDictionaryRef firstAttachment = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, 0));
     338    bool isSync = isCMSampleBufferAttachmentRandomAccess(firstAttachment);
     339    bool isNonDisplaying = isCMSampleBufferAttachmentNonDisplaying(firstAttachment);
     340
     341    for (CFIndex i = 1; i < count; ++i) {
     342        auto attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, i));
     343        if (isSync != isCMSampleBufferAttachmentRandomAccess(attachmentDict))
     344            return false;
     345
     346        if (isNonDisplaying != isCMSampleBufferAttachmentNonDisplaying(attachmentDict))
     347            return false;
     348    };
     349
     350    return true;
     351}
     352
     353Vector<Ref<MediaSampleAVFObjC>> MediaSampleAVFObjC::divideIntoHomogeneousSamples()
     354{
     355    using SampleVector = Vector<Ref<MediaSampleAVFObjC>>;
     356
     357    CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(m_sample.get(), true);
     358    if (!attachmentsArray)
     359        return SampleVector::from(makeRef(*this));
     360
     361    auto count = CFArrayGetCount(attachmentsArray);
     362    if (count <= 1)
     363        return SampleVector::from(makeRef(*this));
     364
     365    CFDictionaryRef firstAttachment = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, 0));
     366    bool isSync = isCMSampleBufferAttachmentRandomAccess(firstAttachment);
     367    bool isNonDisplaying = isCMSampleBufferAttachmentNonDisplaying(firstAttachment);
     368    Vector<CFRange> ranges;
     369    CFIndex currentRangeStart = 0;
     370    CFIndex currentRangeLength = 1;
     371
     372    for (CFIndex i = 1; i < count; ++i, ++currentRangeLength) {
     373        CFDictionaryRef attachmentDict = checked_cf_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachmentsArray, i));
     374        if (isSync == isCMSampleBufferAttachmentRandomAccess(attachmentDict) && isNonDisplaying == isCMSampleBufferAttachmentNonDisplaying(attachmentDict))
     375            continue;
     376
     377        ranges.append(CFRangeMake(currentRangeStart, currentRangeLength));
     378        currentRangeStart = i;
     379        currentRangeLength = 0;
     380    }
     381    ranges.append(CFRangeMake(currentRangeStart, currentRangeLength));
     382
     383    if (ranges.size() == 1)
     384        return SampleVector::from(makeRef(*this));
     385
     386    SampleVector samples;
     387    samples.reserveInitialCapacity(ranges.size());
     388    for (auto& range : ranges) {
     389        CMSampleBufferRef rawSample = nullptr;
     390        if (CMSampleBufferCopySampleBufferForRange(kCFAllocatorDefault, m_sample.get(), range, &rawSample) != noErr || !rawSample)
     391            return { };
     392        samples.uncheckedAppend(MediaSampleAVFObjC::create(adoptCF(rawSample).get(), m_id));
     393    }
     394    return samples;
     395}
     396
     397}
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm

    r256770 r258846  
    599599        return false;
    600600
    601     if (m_client) {
    602         Ref<MediaSample> mediaSample = MediaSampleAVFObjC::create(sampleBuffer, trackID);
    603         DEBUG_LOG(LOGIDENTIFIER, mediaSample.get());
     601    if (!m_client)
     602        return true;
     603
     604    auto mediaSample = MediaSampleAVFObjC::create(sampleBuffer, trackID);
     605
     606    if (mediaSample->isHomogeneous()) {
     607        DEBUG_LOG(LOGIDENTIFIER, mediaSample->toJSONString());
    604608        m_client->sourceBufferPrivateDidReceiveSample(mediaSample);
     609        return true;
     610    }
     611
     612    auto mediaSamples = mediaSample->divideIntoHomogeneousSamples();
     613    for (auto& sample : mediaSamples) {
     614        DEBUG_LOG(LOGIDENTIFIER, sample->toJSONString());
     615        m_client->sourceBufferPrivateDidReceiveSample(sample);
    605616    }
    606617
Note: See TracChangeset for help on using the changeset viewer.