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;
}