Changeset 273461 in webkit
- Timestamp:
- Feb 24, 2021 4:57:53 PM (17 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 7 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/media/media-source/media-source-timestampoffset-trim-expected.txt (added)
-
LayoutTests/media/media-source/media-source-timestampoffset-trim.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/platform/graphics/SourceBufferPrivate.cpp (modified) (11 diffs)
-
Source/WebCore/platform/graphics/SourceBufferPrivate.h (modified) (1 diff)
-
Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (modified) (2 diffs)
-
Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp (modified) (1 diff)
-
Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r273444 r273461 1 2021-02-24 Jean-Yves Avenard <jya@apple.com> 2 3 [MSE] Media segment is incorrectly dropped when using negative timestampOffset or when source buffer appendWindow is set. 4 https://bugs.webkit.org/show_bug.cgi?id=222260 5 6 Reviewed by Eric Carlson. 7 8 * media/media-source/media-source-timestampoffset-trim.html: 9 1 10 2021-02-24 Chris Dumez <cdumez@apple.com> 2 11 -
trunk/Source/WebCore/ChangeLog
r273453 r273461 1 2021-02-24 Jean-Yves Avenard <jya@apple.com> 2 3 [MSE] Media segment is incorrectly dropped when using negative timestampOffset or when source buffer appendWindow is set. 4 https://bugs.webkit.org/show_bug.cgi?id=222260 5 6 Reviewed by Eric Carlson. 7 8 Test: media/media-source/media-source-timestampoffset-trim.html 9 10 CoreMedia packs multiple audio frames together into a single CMSampleBuffer, 11 this allows for faster processing and easier insertion into the track buffer tree. 12 However, per mediasoure spec [1], a frame is to be dropped according to 13 its start time and duration. So if only the beginning of the MediaSample 14 was to be dropped, we would have incorrectly dropped the lot. 15 We now split the MediaSample if it is going to be dropped to ensure that 16 all usable content is inserted into the track buffer. 17 Audio splicing isn't done yet, but this gets us closer to it. 18 19 [1] https://w3c.github.io/media-source/#sourcebuffer-coded-frame-processing 20 21 * platform/graphics/SourceBufferPrivate.cpp: 22 (WebCore::SourceBufferPrivate::didReceiveSample): 23 * platform/graphics/SourceBufferPrivate.h: 24 * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm: 25 (WebCore::SourceBufferPrivateAVFObjC::didParseInitializationData): 26 (WebCore::SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackId): 27 * platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp: 28 (WebCore::SourceBufferPrivateGStreamer::didReceiveSample): 29 * platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h: 30 1 31 2021-02-24 Chris Dumez <cdumez@apple.com> 2 32 -
trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
r272696 r273461 817 817 } 818 818 819 void SourceBufferPrivate::didReceiveSample( MediaSample& sample)819 void SourceBufferPrivate::didReceiveSample(Ref<MediaSample>&& originalSample) 820 820 { 821 821 if (!m_isAttached) … … 843 843 // 1. For each coded frame in the media segment run the following steps: 844 844 // 1.1. Loop Top 845 846 Ref<MediaSample> sample = WTFMove(originalSample); 847 845 848 do { 846 849 MediaTime presentationTimestamp; … … 851 854 // 1.2 Let frame duration be a double precision floating point representation of the coded frame's 852 855 // duration in seconds. 853 MediaTime frameDuration = sample .duration();856 MediaTime frameDuration = sample->duration(); 854 857 855 858 if (m_shouldGenerateTimestamps) { … … 866 869 // 1. Let presentation timestamp be a double precision floating point representation of 867 870 // the coded frame's presentation timestamp in seconds. 868 presentationTimestamp = sample .presentationTime();871 presentationTimestamp = sample->presentationTime(); 869 872 870 873 // 2. Let decode timestamp be a double precision floating point representation of the coded frame's 871 874 // decode timestamp in seconds. 872 decodeTimestamp = sample .decodeTime();875 decodeTimestamp = sample->decodeTime(); 873 876 } 874 877 … … 896 899 // NOTE: this is out-of-order, but we need TrackBuffer to be able to cache the results of timestamp offset rounding 897 900 // 1.5 Let track buffer equal the track buffer that the coded frame will be added to. 898 AtomString trackID = sample .trackID();901 AtomString trackID = sample->trackID(); 899 902 auto it = m_trackBufferMap.find(trackID); 900 903 if (it == m_trackBufferMap.end()) { … … 976 979 if (m_appendMode == SourceBufferAppendMode::Sequence) { 977 980 // Use the generated timestamps instead of the sample's timestamps. 978 sample .setTimestamps(presentationTimestamp, decodeTimestamp);981 sample->setTimestamps(presentationTimestamp, decodeTimestamp); 979 982 } else if (trackBuffer.roundedTimestampOffset) { 980 983 // Reflect the timestamp offset into the sample. 981 sample .offsetTimestampsBy(trackBuffer.roundedTimestampOffset);982 } 983 984 DEBUG_LOG(LOGIDENTIFIER, sample );984 sample->offsetTimestampsBy(trackBuffer.roundedTimestampOffset); 985 } 986 987 DEBUG_LOG(LOGIDENTIFIER, sample.get()); 985 988 986 989 // 1.7 Let frame end timestamp equal the sum of presentation timestamp and frame duration. … … 994 997 // the next coded frame. 995 998 if (presentationTimestamp < m_appendWindowStart || frameEndTimestamp > m_appendWindowEnd) { 999 // 1.8 Note. 1000 // Some implementations MAY choose to collect some of these coded frames with presentation 1001 // timestamp less than appendWindowStart and use them to generate a splice at the first coded 1002 // frame that has a presentation timestamp greater than or equal to appendWindowStart even if 1003 // that frame is not a random access point. Supporting this requires multiple decoders or 1004 // faster than real-time decoding so for now this behavior will not be a normative 1005 // requirement. 1006 // 1.9 Note. 1007 // Some implementations MAY choose to collect coded frames with presentation timestamp less 1008 // than appendWindowEnd and frame end timestamp greater than appendWindowEnd and use them to 1009 // generate a splice across the portion of the collected coded frames within the append 1010 // window at time of collection, and the beginning portion of later processed frames which 1011 // only partially overlap the end of the collected coded frames. Supporting this requires 1012 // multiple decoders or faster than real-time decoding so for now this behavior will not be a 1013 // normative requirement. In conjunction with collecting coded frames that span 1014 // appendWindowStart, implementations MAY thus support gapless audio splicing. 1015 // Audio MediaSamples are typically made of packed audio samples. Trim sample to make it fit within the appendWindow. 1016 if (sample->isDivisable()) { 1017 std::pair<RefPtr<MediaSample>, RefPtr<MediaSample>> replacementSamples = sample->divide(m_appendWindowStart); 1018 if (replacementSamples.second) { 1019 replacementSamples = replacementSamples.second->divide(m_appendWindowEnd); 1020 if (replacementSamples.first) { 1021 sample = replacementSamples.first.releaseNonNull(); 1022 if (m_appendMode != SourceBufferAppendMode::Sequence && trackBuffer.roundedTimestampOffset) 1023 sample->offsetTimestampsBy(-trackBuffer.roundedTimestampOffset); 1024 continue; 1025 } 1026 } 1027 } 996 1028 trackBuffer.needRandomAccessFlag = true; 997 1029 m_client->sourceBufferPrivateDidDropSample(); … … 1014 1046 // 1.11.1 If the coded frame is not a random access point, then drop the coded frame and jump 1015 1047 // to the top of the loop to start processing the next coded frame. 1016 if (!sample .isSync()) {1048 if (!sample->isSync()) { 1017 1049 m_client->sourceBufferPrivateDidDropSample(); 1018 1050 return; … … 1082 1114 // the how the MSE specification should handlie this secnario. 1083 1115 do { 1084 if (!sample .isSync())1116 if (!sample->isSync()) 1085 1117 break; 1086 1118 1087 DecodeOrderSampleMap::KeyType decodeKey(sample .decodeTime(), sample.presentationTime());1119 DecodeOrderSampleMap::KeyType decodeKey(sample->decodeTime(), sample->presentationTime()); 1088 1120 auto nextSampleInDecodeOrder = trackBuffer.samples.decodeOrder().findSampleAfterDecodeKey(decodeKey); 1089 1121 if (nextSampleInDecodeOrder == trackBuffer.samples.decodeOrder().end()) … … 1152 1184 // timestamp < presentationTime, but whose decode timestamp >= decodeTime. These will eventually cause 1153 1185 // a decode error if left in place, so remove these samples as well. 1154 DecodeOrderSampleMap::KeyType decodeKey(sample .decodeTime(), sample.presentationTime());1186 DecodeOrderSampleMap::KeyType decodeKey(sample->decodeTime(), sample->presentationTime()); 1155 1187 auto samplesWithHigherDecodeTimes = trackBuffer.samples.decodeOrder().findSamplesBetweenDecodeKeys(decodeKey, erasedSamples.decodeOrder().begin()->first); 1156 1188 if (samplesWithHigherDecodeTimes.first != samplesWithHigherDecodeTimes.second) … … 1198 1230 // If the frame is after the discontinuity boundary, the enqueueing algorithm will hold it there until samples 1199 1231 // with earlier timestamps are enqueued. The decode queue is not FIFO, but rather an ordered map. 1200 DecodeOrderSampleMap::KeyType decodeKey(sample .decodeTime(), sample.presentationTime());1232 DecodeOrderSampleMap::KeyType decodeKey(sample->decodeTime(), sample->presentationTime()); 1201 1233 if (trackBuffer.lastEnqueuedDecodeKey.first.isInvalid() || decodeKey > trackBuffer.lastEnqueuedDecodeKey) { 1202 trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, &sample ));1203 1204 if (trackBuffer.minimumEnqueuedPresentationTime.isValid() && sample .presentationTime() < trackBuffer.minimumEnqueuedPresentationTime)1234 trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, &sample.get())); 1235 1236 if (trackBuffer.minimumEnqueuedPresentationTime.isValid() && sample->presentationTime() < trackBuffer.minimumEnqueuedPresentationTime) 1205 1237 trackBuffer.needsMinimumUpcomingPresentationTimeUpdating = true; 1206 1238 } -
trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h
r272632 r273461 162 162 void reenqueSamples(const AtomString& trackID); 163 163 WEBCORE_EXPORT void didReceiveInitializationSegment(SourceBufferPrivateClient::InitializationSegment&&, CompletionHandler<void()>&&); 164 WEBCORE_EXPORT void didReceiveSample( MediaSample&);164 WEBCORE_EXPORT void didReceiveSample(Ref<MediaSample>&&); 165 165 void provideMediaData(const AtomString& trackID); 166 166 uint64_t totalTrackBufferSizeInBytes() const; -
trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm
r272439 r273461 410 410 if (trackId == m_enabledVideoTrackID || m_audioRenderers.contains(trackId)) { 411 411 DEBUG_LOG(LOGIDENTIFIER, mediaSample.get()); 412 didReceiveSample( mediaSample);412 didReceiveSample(WTFMove(mediaSample)); 413 413 } 414 414 } … … 451 451 452 452 DEBUG_LOG(LOGIDENTIFIER, mediaSample.get()); 453 didReceiveSample( mediaSample);453 didReceiveSample(WTFMove(mediaSample)); 454 454 } 455 455 -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp
r271056 r273461 187 187 } 188 188 189 void SourceBufferPrivateGStreamer::didReceiveSample( MediaSample& sample)190 { 191 SourceBufferPrivate::didReceiveSample( sample);189 void SourceBufferPrivateGStreamer::didReceiveSample(Ref<MediaSample>&& sample) 190 { 191 SourceBufferPrivate::didReceiveSample(WTFMove(sample)); 192 192 } 193 193 -
trunk/Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h
r270765 r273461 74 74 75 75 void didReceiveInitializationSegment(SourceBufferPrivateClient::InitializationSegment&&, CompletionHandler<void()>&&); 76 void didReceiveSample( MediaSample&);76 void didReceiveSample(Ref<MediaSample>&&); 77 77 void didReceiveAllPendingSamples(); 78 78 void appendParsingFailed();
Note: See TracChangeset
for help on using the changeset viewer.