Add WTF::move()
[WebKit-https.git] / Source / WebCore / Modules / mediasource / SourceBuffer.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "SourceBuffer.h"
33
34 #if ENABLE(MEDIA_SOURCE)
35
36 #include "AudioTrackList.h"
37 #include "Event.h"
38 #include "ExceptionCodePlaceholder.h"
39 #include "GenericEventQueue.h"
40 #include "HTMLMediaElement.h"
41 #include "InbandTextTrack.h"
42 #include "Logging.h"
43 #include "MediaDescription.h"
44 #include "MediaSample.h"
45 #include "MediaSource.h"
46 #include "SampleMap.h"
47 #include "SourceBufferPrivate.h"
48 #include "TextTrackList.h"
49 #include "TimeRanges.h"
50 #include "VideoTrackList.h"
51 #include <map>
52 #include <runtime/JSCInlines.h>
53 #include <runtime/JSLock.h>
54 #include <runtime/VM.h>
55 #include <wtf/CurrentTime.h>
56 #include <wtf/NeverDestroyed.h>
57
58 namespace WebCore {
59
60 static double ExponentialMovingAverageCoefficient = 0.1;
61
62 // Allow hasCurrentTime() to be off by as much as the length of a 24fps video frame
63 static const MediaTime& currentTimeFudgeFactor()
64 {
65     static NeverDestroyed<MediaTime> fudgeFactor(1, 24);
66     return fudgeFactor;
67 }
68
69 struct SourceBuffer::TrackBuffer {
70     MediaTime lastDecodeTimestamp;
71     MediaTime lastFrameDuration;
72     MediaTime highestPresentationTimestamp;
73     MediaTime lastEnqueuedPresentationTime;
74     bool needRandomAccessFlag;
75     bool enabled;
76     SampleMap samples;
77     DecodeOrderSampleMap::MapType decodeQueue;
78     RefPtr<MediaDescription> description;
79
80     TrackBuffer()
81         : lastDecodeTimestamp(MediaTime::invalidTime())
82         , lastFrameDuration(MediaTime::invalidTime())
83         , highestPresentationTimestamp(MediaTime::invalidTime())
84         , lastEnqueuedPresentationTime(MediaTime::invalidTime())
85         , needRandomAccessFlag(true)
86         , enabled(false)
87     {
88     }
89 };
90
91 PassRef<SourceBuffer> SourceBuffer::create(PassRef<SourceBufferPrivate> sourceBufferPrivate, MediaSource* source)
92 {
93     RefPtr<SourceBuffer> sourceBuffer(adoptRef(new SourceBuffer(WTF::move(sourceBufferPrivate), source)));
94     sourceBuffer->suspendIfNeeded();
95     return sourceBuffer.releaseNonNull();
96 }
97
98 SourceBuffer::SourceBuffer(PassRef<SourceBufferPrivate> sourceBufferPrivate, MediaSource* source)
99     : ActiveDOMObject(source->scriptExecutionContext())
100     , m_private(WTF::move(sourceBufferPrivate))
101     , m_source(source)
102     , m_asyncEventQueue(*this)
103     , m_updating(false)
104     , m_appendBufferTimer(this, &SourceBuffer::appendBufferTimerFired)
105     , m_highestPresentationEndTimestamp(MediaTime::invalidTime())
106     , m_receivedFirstInitializationSegment(false)
107     , m_buffered(TimeRanges::create())
108     , m_active(false)
109     , m_appendState(WaitingForSegment)
110     , m_timeOfBufferingMonitor(monotonicallyIncreasingTime())
111     , m_bufferedSinceLastMonitor(0)
112     , m_averageBufferRate(0)
113     , m_reportedExtraMemoryCost(0)
114     , m_pendingRemoveStart(MediaTime::invalidTime())
115     , m_pendingRemoveEnd(MediaTime::invalidTime())
116     , m_removeTimer(this, &SourceBuffer::removeTimerFired)
117 {
118     ASSERT(m_source);
119
120     m_private->setClient(this);
121 }
122
123 SourceBuffer::~SourceBuffer()
124 {
125     ASSERT(isRemoved());
126
127     m_private->setClient(0);
128 }
129
130 PassRefPtr<TimeRanges> SourceBuffer::buffered(ExceptionCode& ec) const
131 {
132     // Section 3.1 buffered attribute steps.
133     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#attributes-1
134     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
135     //    INVALID_STATE_ERR exception and abort these steps.
136     if (isRemoved()) {
137         ec = INVALID_STATE_ERR;
138         return nullptr;
139     }
140
141     // 2. Return a new static normalized TimeRanges object for the media segments buffered.
142     return m_buffered->copy();
143 }
144
145 const RefPtr<TimeRanges>& SourceBuffer::buffered() const
146 {
147     return m_buffered;
148 }
149
150 double SourceBuffer::timestampOffset() const
151 {
152     return m_timestampOffset.toDouble();
153 }
154
155 void SourceBuffer::setTimestampOffset(double offset, ExceptionCode& ec)
156 {
157     // Section 3.1 timestampOffset attribute setter steps.
158     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#attributes-1
159     // 1. Let new timestamp offset equal the new value being assigned to this attribute.
160     // 2. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw an
161     //    INVALID_STATE_ERR exception and abort these steps.
162     // 3. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
163     if (isRemoved() || m_updating) {
164         ec = INVALID_STATE_ERR;
165         return;
166     }
167
168     // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
169     // 4.1 Set the readyState attribute of the parent media source to "open"
170     // 4.2 Queue a task to fire a simple event named sourceopen at the parent media source.
171     m_source->openIfInEndedState();
172
173     // 5. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
174     if (m_appendState == ParsingMediaSegment) {
175         ec = INVALID_STATE_ERR;
176         return;
177     }
178
179     // FIXME: Add step 6 text when mode attribute is implemented.
180     // 7. Update the attribute to the new value.
181     m_timestampOffset = MediaTime::createWithDouble(offset);
182 }
183
184 void SourceBuffer::appendBuffer(PassRefPtr<ArrayBuffer> data, ExceptionCode& ec)
185 {
186     // Section 3.2 appendBuffer()
187     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
188     // 1. If data is null then throw an INVALID_ACCESS_ERR exception and abort these steps.
189     if (!data) {
190         ec = INVALID_ACCESS_ERR;
191         return;
192     }
193
194     appendBufferInternal(static_cast<unsigned char*>(data->data()), data->byteLength(), ec);
195 }
196
197 void SourceBuffer::appendBuffer(PassRefPtr<ArrayBufferView> data, ExceptionCode& ec)
198 {
199     // Section 3.2 appendBuffer()
200     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
201     // 1. If data is null then throw an INVALID_ACCESS_ERR exception and abort these steps.
202     if (!data) {
203         ec = INVALID_ACCESS_ERR;
204         return;
205     }
206
207     appendBufferInternal(static_cast<unsigned char*>(data->baseAddress()), data->byteLength(), ec);
208 }
209
210 void SourceBuffer::abort(ExceptionCode& ec)
211 {
212     // Section 3.2 abort() method steps.
213     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void
214     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source
215     //    then throw an INVALID_STATE_ERR exception and abort these steps.
216     // 2. If the readyState attribute of the parent media source is not in the "open" state
217     //    then throw an INVALID_STATE_ERR exception and abort these steps.
218     if (isRemoved() || !m_source->isOpen()) {
219         ec = INVALID_STATE_ERR;
220         return;
221     }
222
223     // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ...
224     abortIfUpdating();
225
226     // 4. Run the reset parser state algorithm.
227     m_private->abort();
228
229     // FIXME(229408) Add steps 5-6 update appendWindowStart & appendWindowEnd.
230 }
231
232 void SourceBuffer::remove(double start, double end, ExceptionCode& ec)
233 {
234     // Section 3.2 remove() method steps.
235     // 1. If start is negative or greater than duration, then throw an InvalidAccessError exception and abort these steps.
236     // 2. If end is less than or equal to start, then throw an InvalidAccessError exception and abort these steps.
237     if (start < 0 || (m_source && (std::isnan(m_source->duration()) || start > m_source->duration())) || end <= start) {
238         ec = INVALID_ACCESS_ERR;
239         return;
240     }
241
242     // 3. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
243     //    InvalidStateError exception and abort these steps.
244     // 4. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
245     if (isRemoved() || m_updating) {
246         ec = INVALID_ACCESS_ERR;
247         return;
248     }
249
250     // 5. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
251     // 5.1. Set the readyState attribute of the parent media source to "open"
252     // 5.2. Queue a task to fire a simple event named sourceopen at the parent media source .
253     m_source->openIfInEndedState();
254
255     // 6. Set the updating attribute to true.
256     m_updating = true;
257
258     // 7. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
259     scheduleEvent(eventNames().updatestartEvent);
260
261     // 8. Return control to the caller and run the rest of the steps asynchronously.
262     m_pendingRemoveStart = MediaTime::createWithDouble(start);
263     m_pendingRemoveEnd = MediaTime::createWithDouble(end);
264     m_removeTimer.startOneShot(0);
265 }
266
267 void SourceBuffer::abortIfUpdating()
268 {
269     // Section 3.2 abort() method step 3 substeps.
270     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void
271
272     if (!m_updating)
273         return;
274
275     // 3.1. Abort the buffer append and stream append loop algorithms if they are running.
276     m_appendBufferTimer.stop();
277     m_pendingAppendData.clear();
278
279     m_removeTimer.stop();
280     m_pendingRemoveStart = MediaTime::invalidTime();
281     m_pendingRemoveEnd = MediaTime::invalidTime();
282
283     // 3.2. Set the updating attribute to false.
284     m_updating = false;
285
286     // 3.3. Queue a task to fire a simple event named abort at this SourceBuffer object.
287     scheduleEvent(eventNames().abortEvent);
288
289     // 3.4. Queue a task to fire a simple event named updateend at this SourceBuffer object.
290     scheduleEvent(eventNames().updateendEvent);
291 }
292
293 void SourceBuffer::removedFromMediaSource()
294 {
295     if (isRemoved())
296         return;
297
298     abortIfUpdating();
299
300     for (auto& trackBufferPair : m_trackBufferMap.values()) {
301         trackBufferPair.samples.clear();
302         trackBufferPair.decodeQueue.clear();
303     }
304
305     m_private->removedFromMediaSource();
306     m_source = 0;
307 }
308
309 void SourceBuffer::sourceBufferPrivateSeekToTime(SourceBufferPrivate*, const MediaTime& time)
310 {
311     LOG(Media, "SourceBuffer::sourceBufferPrivateSeekToTime(%p)", this);
312
313     for (auto& trackBufferPair : m_trackBufferMap) {
314         TrackBuffer& trackBuffer = trackBufferPair.value;
315         const AtomicString& trackID = trackBufferPair.key;
316
317         // Find the sample which contains the current presentation time.
318         auto currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(time);
319
320         if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end()) {
321             trackBuffer.decodeQueue.clear();
322             m_private->flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample>>(), trackID);
323             continue;
324         }
325
326         // Seach backward for the previous sync sample.
327         MediaTime currentSampleDecodeTime = currentSamplePTSIterator->second->decodeTime();
328         auto currentSampleDTSIterator = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(currentSampleDecodeTime);
329         ASSERT(currentSampleDTSIterator != trackBuffer.samples.decodeOrder().end());
330
331         auto reverseCurrentSampleIter = --DecodeOrderSampleMap::reverse_iterator(currentSampleDTSIterator);
332         auto reverseLastSyncSampleIter = trackBuffer.samples.decodeOrder().findSyncSamplePriorToDecodeIterator(reverseCurrentSampleIter);
333         if (reverseLastSyncSampleIter == trackBuffer.samples.decodeOrder().rend()) {
334             trackBuffer.decodeQueue.clear();
335             m_private->flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample>>(), trackID);
336             continue;
337         }
338
339         Vector<RefPtr<MediaSample>> nonDisplayingSamples;
340         for (auto iter = reverseLastSyncSampleIter; iter != reverseCurrentSampleIter; --iter)
341             nonDisplayingSamples.append(iter->second);
342
343         m_private->flushAndEnqueueNonDisplayingSamples(nonDisplayingSamples, trackID);
344
345         // Fill the decode queue with the remaining samples.
346         trackBuffer.decodeQueue.clear();
347         for (auto iter = currentSampleDTSIterator; iter != trackBuffer.samples.decodeOrder().end(); ++iter)
348             trackBuffer.decodeQueue.insert(*iter);
349
350         provideMediaData(trackBuffer, trackID);
351     }
352
353     m_source->monitorSourceBuffers();
354 }
355
356 MediaTime SourceBuffer::sourceBufferPrivateFastSeekTimeForMediaTime(SourceBufferPrivate*, const MediaTime& targetTime, const MediaTime& negativeThreshold, const MediaTime& positiveThreshold)
357 {
358     MediaTime seekTime = targetTime;
359     MediaTime lowerBoundTime = targetTime - negativeThreshold;
360     MediaTime upperBoundTime = targetTime + positiveThreshold;
361
362     for (auto& trackBuffer : m_trackBufferMap.values()) {
363         // Find the sample which contains the target time time.
364         auto futureSyncSampleIterator = trackBuffer.samples.decodeOrder().findSyncSampleAfterPresentationTime(targetTime, positiveThreshold);
365         auto pastSyncSampleIterator = trackBuffer.samples.decodeOrder().findSyncSamplePriorToPresentationTime(targetTime, negativeThreshold);
366         auto upperBound = trackBuffer.samples.decodeOrder().end();
367         auto lowerBound = trackBuffer.samples.decodeOrder().rend();
368
369         if (futureSyncSampleIterator == upperBound && pastSyncSampleIterator == lowerBound)
370             continue;
371
372         MediaTime futureSeekTime = MediaTime::positiveInfiniteTime();
373         if (futureSyncSampleIterator != upperBound) {
374             RefPtr<MediaSample>& sample = futureSyncSampleIterator->second;
375             futureSeekTime = sample->presentationTime();
376         }
377
378         MediaTime pastSeekTime = MediaTime::negativeInfiniteTime();
379         if (pastSyncSampleIterator != lowerBound) {
380             RefPtr<MediaSample>& sample = pastSyncSampleIterator->second;
381             pastSeekTime = sample->presentationTime();
382         }
383
384         MediaTime trackSeekTime = abs(targetTime - futureSeekTime) < abs(targetTime - pastSeekTime) ? futureSeekTime : pastSeekTime;
385         if (abs(targetTime - trackSeekTime) > abs(targetTime - seekTime))
386             seekTime = trackSeekTime;
387     }
388
389     return seekTime;
390 }
391
392 bool SourceBuffer::hasPendingActivity() const
393 {
394     return m_source || m_asyncEventQueue.hasPendingEvents();
395 }
396
397 void SourceBuffer::stop()
398 {
399     m_appendBufferTimer.stop();
400     m_removeTimer.stop();
401 }
402
403 bool SourceBuffer::isRemoved() const
404 {
405     return !m_source;
406 }
407
408 void SourceBuffer::scheduleEvent(const AtomicString& eventName)
409 {
410     RefPtr<Event> event = Event::create(eventName, false, false);
411     event->setTarget(this);
412
413     m_asyncEventQueue.enqueueEvent(event.release());
414 }
415
416 void SourceBuffer::appendBufferInternal(unsigned char* data, unsigned size, ExceptionCode& ec)
417 {
418     // Section 3.2 appendBuffer()
419     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
420
421     // Step 1 is enforced by the caller.
422     // 2. Run the prepare append algorithm.
423     // Section 3.5.4 Prepare AppendAlgorithm
424
425     // 1. If the SourceBuffer has been removed from the sourceBuffers attribute of the parent media source
426     // then throw an INVALID_STATE_ERR exception and abort these steps.
427     // 2. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
428     if (isRemoved() || m_updating) {
429         ec = INVALID_STATE_ERR;
430         return;
431     }
432
433     // 3. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
434     // 3.1. Set the readyState attribute of the parent media source to "open"
435     // 3.2. Queue a task to fire a simple event named sourceopen at the parent media source .
436     m_source->openIfInEndedState();
437
438     // 4. Run the coded frame eviction algorithm.
439     m_private->evictCodedFrames();
440
441     // 5. If the buffer full flag equals true, then throw a QUOTA_EXCEEDED_ERR exception and abort these step.
442     if (m_private->isFull()) {
443         ec = QUOTA_EXCEEDED_ERR;
444         return;
445     }
446
447     // NOTE: Return to 3.2 appendBuffer()
448     // 3. Add data to the end of the input buffer.
449     m_pendingAppendData.append(data, size);
450
451     // 4. Set the updating attribute to true.
452     m_updating = true;
453
454     // 5. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
455     scheduleEvent(eventNames().updatestartEvent);
456
457     // 6. Asynchronously run the buffer append algorithm.
458     m_appendBufferTimer.startOneShot(0);
459
460     reportExtraMemoryCost();
461 }
462
463 void SourceBuffer::appendBufferTimerFired(Timer<SourceBuffer>&)
464 {
465     if (isRemoved())
466         return;
467
468     ASSERT(m_updating);
469
470     // Section 3.5.5 Buffer Append Algorithm
471     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
472
473     // 1. Run the segment parser loop algorithm.
474     size_t appendSize = m_pendingAppendData.size();
475     if (!appendSize) {
476         // Resize buffer for 0 byte appends so we always have a valid pointer.
477         // We need to convey all appends, even 0 byte ones to |m_private| so
478         // that it can clear its end of stream state if necessary.
479         m_pendingAppendData.resize(1);
480     }
481
482     // Section 3.5.1 Segment Parser Loop
483     // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebuffer-segment-parser-loop
484     // When the segment parser loop algorithm is invoked, run the following steps:
485
486     // 1. Loop Top: If the input buffer is empty, then jump to the need more data step below.
487     if (!m_pendingAppendData.size()) {
488         sourceBufferPrivateAppendComplete(&m_private.get(), AppendSucceeded);
489         return;
490     }
491
492     m_private->append(m_pendingAppendData.data(), appendSize);
493     m_pendingAppendData.clear();
494 }
495
496 void SourceBuffer::sourceBufferPrivateAppendComplete(SourceBufferPrivate*, AppendResult result)
497 {
498     if (isRemoved())
499         return;
500
501     // Section 3.5.5 Buffer Append Algorithm, ctd.
502     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
503
504     // 2. If the input buffer contains bytes that violate the SourceBuffer byte stream format specification,
505     // then run the end of stream algorithm with the error parameter set to "decode" and abort this algorithm.
506     if (result == ParsingFailed) {
507         m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
508         return;
509     }
510
511     // NOTE: Steps 3 - 6 enforced by sourceBufferPrivateDidReceiveInitializationSegment() and
512     // sourceBufferPrivateDidReceiveSample below.
513
514     // 7. Need more data: Return control to the calling algorithm.
515
516     // NOTE: return to Section 3.5.5
517     // 2.If the segment parser loop algorithm in the previous step was aborted, then abort this algorithm.
518     if (result != AppendSucceeded)
519         return;
520
521     // 3. Set the updating attribute to false.
522     m_updating = false;
523
524     // 4. Queue a task to fire a simple event named update at this SourceBuffer object.
525     scheduleEvent(eventNames().updateEvent);
526
527     // 5. Queue a task to fire a simple event named updateend at this SourceBuffer object.
528     scheduleEvent(eventNames().updateendEvent);
529
530     if (m_source)
531         m_source->monitorSourceBuffers();
532     for (auto& trackBufferPair : m_trackBufferMap)
533         provideMediaData(trackBufferPair.value, trackBufferPair.key);
534
535     reportExtraMemoryCost();
536 }
537
538 void SourceBuffer::sourceBufferPrivateDidReceiveRenderingError(SourceBufferPrivate*, int)
539 {
540     if (!isRemoved())
541         m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
542 }
543
544 void SourceBuffer::removeCodedFrames(const MediaTime& start, const MediaTime& end)
545 {
546     // 3.5.9 Coded Frame Removal Algorithm
547     // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebuffer-coded-frame-removal
548
549     // 1. Let start be the starting presentation timestamp for the removal range.
550     MediaTime durationMediaTime = MediaTime::createWithDouble(m_source->duration());
551     MediaTime currentMediaTime = MediaTime::createWithDouble(m_source->currentTime());
552
553     // 2. Let end be the end presentation timestamp for the removal range.
554     // 3. For each track buffer in this source buffer, run the following steps:
555     for (auto& iter : m_trackBufferMap) {
556         TrackBuffer& trackBuffer = iter.value;
557
558         // 3.1. Let remove end timestamp be the current value of duration
559         // 3.2 If this track buffer has a random access point timestamp that is greater than or equal to end, then update
560         // remove end timestamp to that random access point timestamp.
561         // NOTE: findSyncSampleAfterPresentationTime will return the next sync sample on or after the presentation time
562         // or decodeOrder().end() if no sync sample exists after that presentation time.
563         DecodeOrderSampleMap::iterator removeDecodeEnd = trackBuffer.samples.decodeOrder().findSyncSampleAfterPresentationTime(end);
564
565         // 3.3 Remove all media data, from this track buffer, that contain starting timestamps greater than or equal to
566         // start and less than the remove end timestamp.
567         // NOTE: frames must be removed in decode order, so that all dependant frames between the frame to be removed
568         // and the next sync sample frame are removed.
569         PresentationOrderSampleMap::iterator removePresentaionStart = trackBuffer.samples.presentationOrder().findSampleAfterPresentationTime(start);
570         DecodeOrderSampleMap::iterator removeDecodeStart = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(removePresentaionStart->second->decodeTime());
571         DecodeOrderSampleMap::MapType erasedSamples(removeDecodeStart, removeDecodeEnd);
572         RefPtr<TimeRanges> erasedRanges = TimeRanges::create();
573         MediaTime microsecond(1, 1000000);
574         for (auto erasedIt : erasedSamples) {
575             trackBuffer.samples.removeSample(erasedIt.second.get());
576             double startTime = erasedIt.first.toDouble();
577             double endTime = ((erasedIt.first + erasedIt.second->duration()) + microsecond).toDouble();
578             erasedRanges->add(startTime, endTime);
579         }
580
581         erasedRanges->invert();
582         m_buffered->intersectWith(*erasedRanges);
583
584         // 3.4 If this object is in activeSourceBuffers, the current playback position is greater than or equal to start
585         // and less than the remove end timestamp, and HTMLMediaElement.readyState is greater than HAVE_METADATA, then set
586         // the HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback.
587         if (m_active && currentMediaTime >= start && currentMediaTime < end && m_private->readyState() > MediaPlayer::HaveMetadata)
588             m_private->setReadyState(MediaPlayer::HaveMetadata);
589     }
590
591     // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
592     // No-op
593 }
594
595 void SourceBuffer::removeTimerFired(Timer<SourceBuffer>*)
596 {
597     ASSERT(m_updating);
598     ASSERT(m_pendingRemoveStart.isValid());
599     ASSERT(m_pendingRemoveStart < m_pendingRemoveEnd);
600
601     // Section 3.2 remove() method steps
602     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-remove-void-double-start-double-end
603
604     // 9. Run the coded frame removal algorithm with start and end as the start and end of the removal range.
605     removeCodedFrames(m_pendingRemoveStart, m_pendingRemoveEnd);
606
607     // 10. Set the updating attribute to false.
608     m_updating = false;
609     m_pendingRemoveStart = MediaTime::invalidTime();
610     m_pendingRemoveEnd = MediaTime::invalidTime();
611
612     // 11. Queue a task to fire a simple event named update at this SourceBuffer object.
613     scheduleEvent(eventNames().updateEvent);
614
615     // 12. Queue a task to fire a simple event named updateend at this SourceBuffer object.
616     scheduleEvent(eventNames().updateendEvent);
617 }
618
619 const AtomicString& SourceBuffer::decodeError()
620 {
621     static NeverDestroyed<AtomicString> decode("decode", AtomicString::ConstructFromLiteral);
622     return decode;
623 }
624
625 const AtomicString& SourceBuffer::networkError()
626 {
627     static NeverDestroyed<AtomicString> network("network", AtomicString::ConstructFromLiteral);
628     return network;
629 }
630
631 VideoTrackList* SourceBuffer::videoTracks()
632 {
633     if (!m_source || !m_source->mediaElement())
634         return nullptr;
635
636     if (!m_videoTracks)
637         m_videoTracks = VideoTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
638
639     return m_videoTracks.get();
640 }
641
642 AudioTrackList* SourceBuffer::audioTracks()
643 {
644     if (!m_source || !m_source->mediaElement())
645         return nullptr;
646
647     if (!m_audioTracks)
648         m_audioTracks = AudioTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
649
650     return m_audioTracks.get();
651 }
652
653 TextTrackList* SourceBuffer::textTracks()
654 {
655     if (!m_source || !m_source->mediaElement())
656         return nullptr;
657
658     if (!m_textTracks)
659         m_textTracks = TextTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
660
661     return m_textTracks.get();
662 }
663
664 void SourceBuffer::setActive(bool active)
665 {
666     if (m_active == active)
667         return;
668
669     m_active = active;
670     m_private->setActive(active);
671     if (!isRemoved())
672         m_source->sourceBufferDidChangeAcitveState(this, active);
673 }
674
675 void SourceBuffer::sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const WTF::AtomicString& error)
676 {
677     if (!isRemoved())
678         m_source->streamEndedWithError(error, IgnorableExceptionCode());
679 }
680
681 void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment& segment)
682 {
683     if (isRemoved())
684         return;
685
686     // 3.5.7 Initialization Segment Received
687     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-init-segment-received
688     // 1. Update the duration attribute if it currently equals NaN:
689     if (std::isnan(m_source->duration())) {
690         // ↳ If the initialization segment contains a duration:
691         //   Run the duration change algorithm with new duration set to the duration in the initialization segment.
692         // ↳ Otherwise:
693         //   Run the duration change algorithm with new duration set to positive Infinity.
694         MediaTime newDuration = segment.duration.isValid() ? segment.duration : MediaTime::positiveInfiniteTime();
695         m_source->setDuration(newDuration.toDouble(), IGNORE_EXCEPTION);
696     }
697
698     // 2. If the initialization segment has no audio, video, or text tracks, then run the end of stream
699     // algorithm with the error parameter set to "decode" and abort these steps.
700     if (!segment.audioTracks.size() && !segment.videoTracks.size() && !segment.textTracks.size())
701         m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
702
703
704     // 3. If the first initialization segment flag is true, then run the following steps:
705     if (m_receivedFirstInitializationSegment) {
706         if (!validateInitializationSegment(segment)) {
707             m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
708             return;
709         }
710         // 3.2 Add the appropriate track descriptions from this initialization segment to each of the track buffers.
711         ASSERT(segment.audioTracks.size() == audioTracks()->length());
712         for (auto& audioTrackInfo : segment.audioTracks) {
713             if (audioTracks()->length() == 1) {
714                 audioTracks()->item(0)->setPrivate(audioTrackInfo.track);
715                 break;
716             }
717
718             auto audioTrack = audioTracks()->getTrackById(audioTrackInfo.track->id());
719             ASSERT(audioTrack);
720             audioTrack->setPrivate(audioTrackInfo.track);
721         }
722
723         ASSERT(segment.videoTracks.size() == videoTracks()->length());
724         for (auto& videoTrackInfo : segment.videoTracks) {
725             if (videoTracks()->length() == 1) {
726                 videoTracks()->item(0)->setPrivate(videoTrackInfo.track);
727                 break;
728             }
729
730             auto videoTrack = videoTracks()->getTrackById(videoTrackInfo.track->id());
731             ASSERT(videoTrack);
732             videoTrack->setPrivate(videoTrackInfo.track);
733         }
734
735         ASSERT(segment.textTracks.size() == textTracks()->length());
736         for (auto& textTrackInfo : segment.textTracks) {
737             if (textTracks()->length() == 1) {
738                 toInbandTextTrack(textTracks()->item(0))->setPrivate(textTrackInfo.track);
739                 break;
740             }
741
742             auto textTrack = textTracks()->getTrackById(textTrackInfo.track->id());
743             ASSERT(textTrack);
744             toInbandTextTrack(textTrack)->setPrivate(textTrackInfo.track);
745         }
746
747         for (auto& trackBuffer : m_trackBufferMap.values())
748             trackBuffer.needRandomAccessFlag = true;
749     }
750
751     // 4. Let active track flag equal false.
752     bool activeTrackFlag = false;
753
754     // 5. If the first initialization segment flag is false, then run the following steps:
755     if (!m_receivedFirstInitializationSegment) {
756         // 5.1 If the initialization segment contains tracks with codecs the user agent does not support,
757         // then run the end of stream algorithm with the error parameter set to "decode" and abort these steps.
758         // NOTE: This check is the responsibility of the SourceBufferPrivate.
759
760         // 5.2 For each audio track in the initialization segment, run following steps:
761         for (auto& audioTrackInfo : segment.audioTracks) {
762             AudioTrackPrivate* audioTrackPrivate = audioTrackInfo.track.get();
763
764             // 5.2.1 Let new audio track be a new AudioTrack object.
765             // 5.2.2 Generate a unique ID and assign it to the id property on new video track.
766             RefPtr<AudioTrack> newAudioTrack = AudioTrack::create(this, audioTrackPrivate);
767             newAudioTrack->setSourceBuffer(this);
768
769             // 5.2.3 If audioTracks.length equals 0, then run the following steps:
770             if (!audioTracks()->length()) {
771                 // 5.2.3.1 Set the enabled property on new audio track to true.
772                 newAudioTrack->setEnabled(true);
773
774                 // 5.2.3.2 Set active track flag to true.
775                 activeTrackFlag = true;
776             }
777
778             // 5.2.4 Add new audio track to the audioTracks attribute on this SourceBuffer object.
779             // 5.2.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
780             // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
781             // referenced by the audioTracks attribute on this SourceBuffer object.
782             audioTracks()->append(newAudioTrack);
783
784             // 5.2.6 Add new audio track to the audioTracks attribute on the HTMLMediaElement.
785             // 5.2.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
786             // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
787             // referenced by the audioTracks attribute on the HTMLMediaElement.
788             m_source->mediaElement()->audioTracks()->append(newAudioTrack);
789
790             // 5.2.8 Create a new track buffer to store coded frames for this track.
791             ASSERT(!m_trackBufferMap.contains(newAudioTrack->id()));
792             TrackBuffer& trackBuffer = m_trackBufferMap.add(newAudioTrack->id(), TrackBuffer()).iterator->value;
793
794             // 5.2.9 Add the track description for this track to the track buffer.
795             trackBuffer.description = audioTrackInfo.description;
796
797             m_audioCodecs.append(trackBuffer.description->codec());
798         }
799
800         // 5.3 For each video track in the initialization segment, run following steps:
801         for (auto& videoTrackInfo : segment.videoTracks) {
802             VideoTrackPrivate* videoTrackPrivate = videoTrackInfo.track.get();
803
804             // 5.3.1 Let new video track be a new VideoTrack object.
805             // 5.3.2 Generate a unique ID and assign it to the id property on new video track.
806             RefPtr<VideoTrack> newVideoTrack = VideoTrack::create(this, videoTrackPrivate);
807             newVideoTrack->setSourceBuffer(this);
808
809             // 5.3.3 If videoTracks.length equals 0, then run the following steps:
810             if (!videoTracks()->length()) {
811                 // 5.3.3.1 Set the selected property on new video track to true.
812                 newVideoTrack->setSelected(true);
813
814                 // 5.3.3.2 Set active track flag to true.
815                 activeTrackFlag = true;
816             }
817
818             // 5.3.4 Add new video track to the videoTracks attribute on this SourceBuffer object.
819             // 5.3.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
820             // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
821             // referenced by the videoTracks attribute on this SourceBuffer object.
822             videoTracks()->append(newVideoTrack);
823
824             // 5.3.6 Add new video track to the videoTracks attribute on the HTMLMediaElement.
825             // 5.3.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
826             // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
827             // referenced by the videoTracks attribute on the HTMLMediaElement.
828             m_source->mediaElement()->videoTracks()->append(newVideoTrack);
829
830             // 5.3.8 Create a new track buffer to store coded frames for this track.
831             ASSERT(!m_trackBufferMap.contains(newVideoTrack->id()));
832             TrackBuffer& trackBuffer = m_trackBufferMap.add(newVideoTrack->id(), TrackBuffer()).iterator->value;
833
834             // 5.3.9 Add the track description for this track to the track buffer.
835             trackBuffer.description = videoTrackInfo.description;
836
837             m_videoCodecs.append(trackBuffer.description->codec());
838         }
839
840         // 5.4 For each text track in the initialization segment, run following steps:
841         for (auto& textTrackInfo : segment.textTracks) {
842             InbandTextTrackPrivate* textTrackPrivate = textTrackInfo.track.get();
843
844             // 5.4.1 Let new text track be a new TextTrack object with its properties populated with the
845             // appropriate information from the initialization segment.
846             RefPtr<InbandTextTrack> newTextTrack = InbandTextTrack::create(scriptExecutionContext(), this, textTrackPrivate);
847
848             // 5.4.2 If the mode property on new text track equals "showing" or "hidden", then set active
849             // track flag to true.
850             if (textTrackPrivate->mode() != InbandTextTrackPrivate::Disabled)
851                 activeTrackFlag = true;
852
853             // 5.4.3 Add new text track to the textTracks attribute on this SourceBuffer object.
854             // 5.4.4 Queue a task to fire a trusted event named addtrack, that does not bubble and is
855             // not cancelable, and that uses the TrackEvent interface, at textTracks attribute on this
856             // SourceBuffer object.
857             textTracks()->append(newTextTrack);
858
859             // 5.4.5 Add new text track to the textTracks attribute on the HTMLMediaElement.
860             // 5.4.6 Queue a task to fire a trusted event named addtrack, that does not bubble and is
861             // not cancelable, and that uses the TrackEvent interface, at the TextTrackList object
862             // referenced by the textTracks attribute on the HTMLMediaElement.
863             m_source->mediaElement()->textTracks()->append(newTextTrack);
864
865             // 5.4.7 Create a new track buffer to store coded frames for this track.
866             ASSERT(!m_trackBufferMap.contains(textTrackPrivate->id()));
867             TrackBuffer& trackBuffer = m_trackBufferMap.add(textTrackPrivate->id(), TrackBuffer()).iterator->value;
868
869             // 5.4.8 Add the track description for this track to the track buffer.
870             trackBuffer.description = textTrackInfo.description;
871
872             m_textCodecs.append(trackBuffer.description->codec());
873         }
874
875         // 5.5 If active track flag equals true, then run the following steps:
876         if (activeTrackFlag) {
877             // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
878             setActive(true);
879         }
880
881         // 5.6 Set first initialization segment flag to true.
882         m_receivedFirstInitializationSegment = true;
883     }
884
885     // 6. If the HTMLMediaElement.readyState attribute is HAVE_NOTHING, then run the following steps:
886     if (m_private->readyState() == MediaPlayer::HaveNothing) {
887         // 6.1 If one or more objects in sourceBuffers have first initialization segment flag set to false, then abort these steps.
888         for (auto& sourceBuffer : *m_source->sourceBuffers()) {
889             if (!sourceBuffer->m_receivedFirstInitializationSegment)
890                 return;
891         }
892
893         // 6.2 Set the HTMLMediaElement.readyState attribute to HAVE_METADATA.
894         // 6.3 Queue a task to fire a simple event named loadedmetadata at the media element.
895         m_private->setReadyState(MediaPlayer::HaveMetadata);
896     }
897
898     // 7. If the active track flag equals true and the HTMLMediaElement.readyState
899     // attribute is greater than HAVE_CURRENT_DATA, then set the HTMLMediaElement.readyState
900     // attribute to HAVE_METADATA.
901     if (activeTrackFlag && m_private->readyState() > MediaPlayer::HaveCurrentData)
902         m_private->setReadyState(MediaPlayer::HaveMetadata);
903 }
904
905 bool SourceBuffer::validateInitializationSegment(const InitializationSegment& segment)
906 {
907     // 3.5.7 Initialization Segment Received (ctd)
908     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-init-segment-received
909
910     // 3.1. Verify the following properties. If any of the checks fail then run the end of stream
911     // algorithm with the error parameter set to "decode" and abort these steps.
912     //   * The number of audio, video, and text tracks match what was in the first initialization segment.
913     if (segment.audioTracks.size() != audioTracks()->length()
914         || segment.videoTracks.size() != videoTracks()->length()
915         || segment.textTracks.size() != textTracks()->length())
916         return false;
917
918     //   * The codecs for each track, match what was specified in the first initialization segment.
919     for (auto& audioTrackInfo : segment.audioTracks) {
920         if (!m_audioCodecs.contains(audioTrackInfo.description->codec()))
921             return false;
922     }
923
924     for (auto& videoTrackInfo : segment.videoTracks) {
925         if (!m_videoCodecs.contains(videoTrackInfo.description->codec()))
926             return false;
927     }
928
929     for (auto& textTrackInfo : segment.textTracks) {
930         if (!m_textCodecs.contains(textTrackInfo.description->codec()))
931             return false;
932     }
933
934     //   * If more than one track for a single type are present (ie 2 audio tracks), then the Track
935     //   IDs match the ones in the first initialization segment.
936     if (segment.audioTracks.size() >= 2) {
937         for (auto& audioTrackInfo : segment.audioTracks) {
938             if (!m_trackBufferMap.contains(audioTrackInfo.track->id()))
939                 return false;
940         }
941     }
942
943     if (segment.videoTracks.size() >= 2) {
944         for (auto& videoTrackInfo : segment.videoTracks) {
945             if (!m_trackBufferMap.contains(videoTrackInfo.track->id()))
946                 return false;
947         }
948     }
949
950     if (segment.textTracks.size() >= 2) {
951         for (auto& textTrackInfo : segment.videoTracks) {
952             if (!m_trackBufferMap.contains(textTrackInfo.track->id()))
953                 return false;
954         }
955     }
956
957     return true;
958 }
959
960 class SampleLessThanComparator {
961 public:
962     bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
963     {
964         return value1.first < value2.first;
965     }
966
967     bool operator()(MediaTime value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
968     {
969         return value1 < value2.first;
970     }
971
972     bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, MediaTime value2)
973     {
974         return value1.first < value2;
975     }
976 };
977
978 void SourceBuffer::sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample> prpSample)
979 {
980     if (isRemoved())
981         return;
982
983     RefPtr<MediaSample> sample = prpSample;
984
985     // 3.5.8 Coded Frame Processing
986     // When complete coded frames have been parsed by the segment parser loop then the following steps
987     // are run:
988     // 1. For each coded frame in the media segment run the following steps:
989     // 1.1. Loop Top
990     do {
991         // 1.1 (ctd) Let presentation timestamp be a double precision floating point representation of
992         // the coded frame's presentation timestamp in seconds.
993         MediaTime presentationTimestamp = sample->presentationTime();
994
995         // 1.2 Let decode timestamp be a double precision floating point representation of the coded frame's
996         // decode timestamp in seconds.
997         MediaTime decodeTimestamp = sample->decodeTime();
998
999         // 1.3 Let frame duration be a double precision floating point representation of the coded frame's
1000         // duration in seconds.
1001         MediaTime frameDuration = sample->duration();
1002
1003         // 1.4 If mode equals "sequence" and group start timestamp is set, then run the following steps:
1004         // FIXME: add support for "sequence" mode
1005
1006         // 1.5 If timestampOffset is not 0, then run the following steps:
1007         if (m_timestampOffset != MediaTime::zeroTime()) {
1008             // 1.5.1 Add timestampOffset to the presentation timestamp.
1009             presentationTimestamp += m_timestampOffset;
1010
1011             // 1.5.2 Add timestampOffset to the decode timestamp.
1012             decodeTimestamp += m_timestampOffset;
1013
1014             // 1.5.3 If the presentation timestamp or decode timestamp is less than the presentation start
1015             // time, then run the end of stream algorithm with the error parameter set to "decode", and
1016             // abort these steps.
1017             MediaTime presentationStartTime = MediaTime::zeroTime();
1018             if (presentationTimestamp < presentationStartTime || decodeTimestamp < presentationStartTime) {
1019                 m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
1020                 return;
1021             }
1022         }
1023
1024         // 1.6 Let track buffer equal the track buffer that the coded frame will be added to.
1025         AtomicString trackID = sample->trackID();
1026         auto it = m_trackBufferMap.find(trackID);
1027         if (it == m_trackBufferMap.end())
1028             it = m_trackBufferMap.add(trackID, TrackBuffer()).iterator;
1029         TrackBuffer& trackBuffer = it->value;
1030
1031         // 1.7 If last decode timestamp for track buffer is set and decode timestamp is less than last
1032         // decode timestamp:
1033         // OR
1034         // If last decode timestamp for track buffer is set and the difference between decode timestamp and
1035         // last decode timestamp is greater than 2 times last frame duration:
1036         if (trackBuffer.lastDecodeTimestamp.isValid() && (decodeTimestamp < trackBuffer.lastDecodeTimestamp
1037             || abs(decodeTimestamp - trackBuffer.lastDecodeTimestamp) > (trackBuffer.lastFrameDuration * 2))) {
1038             // 1.7.1 If mode equals "segments":
1039             // Set highest presentation end timestamp to presentation timestamp.
1040             m_highestPresentationEndTimestamp = presentationTimestamp;
1041
1042             // If mode equals "sequence":
1043             // Set group start timestamp equal to the highest presentation end timestamp.
1044             // FIXME: Add support for "sequence" mode.
1045
1046             for (auto& trackBuffer : m_trackBufferMap.values()) {
1047                 // 1.7.2 Unset the last decode timestamp on all track buffers.
1048                 trackBuffer.lastDecodeTimestamp = MediaTime::invalidTime();
1049                 // 1.7.3 Unset the last frame duration on all track buffers.
1050                 trackBuffer.lastFrameDuration = MediaTime::invalidTime();
1051                 // 1.7.4 Unset the highest presentation timestamp on all track buffers.
1052                 trackBuffer.highestPresentationTimestamp = MediaTime::invalidTime();
1053                 // 1.7.5 Set the need random access point flag on all track buffers to true.
1054                 trackBuffer.needRandomAccessFlag = true;
1055             }
1056
1057             // 1.7.6 Jump to the Loop Top step above to restart processing of the current coded frame.
1058             continue;
1059         }
1060
1061         // 1.8 Let frame end timestamp equal the sum of presentation timestamp and frame duration.
1062         MediaTime frameEndTimestamp = presentationTimestamp + frameDuration;
1063
1064         // 1.9 If presentation timestamp is less than appendWindowStart, then set the need random access
1065         // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
1066         // the next coded frame.
1067         // 1.10 If frame end timestamp is greater than appendWindowEnd, then set the need random access
1068         // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
1069         // the next coded frame.
1070         // FIXME: implement append windows
1071
1072         // 1.11 If the need random access point flag on track buffer equals true, then run the following steps:
1073         if (trackBuffer.needRandomAccessFlag) {
1074             // 1.11.1 If the coded frame is not a random access point, then drop the coded frame and jump
1075             // to the top of the loop to start processing the next coded frame.
1076             if (!sample->isSync()) {
1077                 didDropSample();
1078                 return;
1079             }
1080
1081             // 1.11.2 Set the need random access point flag on track buffer to false.
1082             trackBuffer.needRandomAccessFlag = false;
1083         }
1084
1085         // 1.12 Let spliced audio frame be an unset variable for holding audio splice information
1086         // 1.13 Let spliced timed text frame be an unset variable for holding timed text splice information
1087         // FIXME: Add support for sample splicing.
1088
1089         DecodeOrderSampleMap::MapType erasedSamples;
1090         MediaTime microsecond(1, 1000000);
1091
1092         // 1.14 If last decode timestamp for track buffer is unset and presentation timestamp falls
1093         // falls within the presentation interval of a coded frame in track buffer, then run the
1094         // following steps:
1095         if (trackBuffer.lastDecodeTimestamp.isInvalid()) {
1096             auto iter = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(presentationTimestamp);
1097             if (iter != trackBuffer.samples.presentationOrder().end()) {
1098                 // 1.14.1 Let overlapped frame be the coded frame in track buffer that matches the condition above.
1099                 RefPtr<MediaSample> overlappedFrame = iter->second;
1100
1101                 // 1.14.2 If track buffer contains audio coded frames:
1102                 // Run the audio splice frame algorithm and if a splice frame is returned, assign it to
1103                 // spliced audio frame.
1104                 // FIXME: Add support for sample splicing.
1105
1106                 // If track buffer contains video coded frames:
1107                 if (trackBuffer.description->isVideo()) {
1108                     // 1.14.2.1 Let overlapped frame presentation timestamp equal the presentation timestamp
1109                     // of overlapped frame.
1110                     MediaTime overlappedFramePresentationTimestamp = overlappedFrame->presentationTime();
1111
1112                     // 1.14.2.2 Let remove window timestamp equal overlapped frame presentation timestamp
1113                     // plus 1 microsecond.
1114                     MediaTime removeWindowTimestamp = overlappedFramePresentationTimestamp + microsecond;
1115
1116                     // 1.14.2.3 If the presentation timestamp is less than the remove window timestamp,
1117                     // then remove overlapped frame and any coded frames that depend on it from track buffer.
1118                     if (presentationTimestamp < removeWindowTimestamp)
1119                         erasedSamples.insert(*iter);
1120                 }
1121
1122                 // If track buffer contains timed text coded frames:
1123                 // Run the text splice frame algorithm and if a splice frame is returned, assign it to spliced timed text frame.
1124                 // FIXME: Add support for sample splicing.
1125             }
1126         }
1127
1128         // 1.15 Remove existing coded frames in track buffer:
1129         // If highest presentation timestamp for track buffer is not set:
1130         if (trackBuffer.highestPresentationTimestamp.isInvalid()) {
1131             // Remove all coded frames from track buffer that have a presentation timestamp greater than or
1132             // equal to presentation timestamp and less than frame end timestamp.
1133             auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesBetweenPresentationTimes(presentationTimestamp, frameEndTimestamp);
1134             if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
1135                 erasedSamples.insert(iter_pair.first, iter_pair.second);
1136         }
1137
1138         // If highest presentation timestamp for track buffer is set and less than presentation timestamp
1139         if (trackBuffer.highestPresentationTimestamp.isValid() && trackBuffer.highestPresentationTimestamp <= presentationTimestamp) {
1140             // Remove all coded frames from track buffer that have a presentation timestamp greater than highest
1141             // presentation timestamp and less than or equal to frame end timestamp.
1142             auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
1143             if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
1144                 erasedSamples.insert(iter_pair.first, iter_pair.second);
1145         }
1146
1147         // 1.16 Remove decoding dependencies of the coded frames removed in the previous step:
1148         DecodeOrderSampleMap::MapType dependentSamples;
1149         if (!erasedSamples.empty()) {
1150             // If detailed information about decoding dependencies is available:
1151             // FIXME: Add support for detailed dependency information
1152
1153             // Otherwise: Remove all coded frames between the coded frames removed in the previous step
1154             // and the next random access point after those removed frames.
1155             for (auto& samplePair : erasedSamples) {
1156                 auto currentDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(samplePair.second->decodeTime());
1157                 auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(currentDecodeIter);
1158                 dependentSamples.insert(currentDecodeIter, nextSyncIter);
1159             }
1160
1161
1162             RefPtr<TimeRanges> erasedRanges = TimeRanges::create();
1163             for (auto& samplePair : erasedSamples) {
1164                 MediaTime startTime = samplePair.second->presentationTime();
1165                 MediaTime endTime = startTime + samplePair.second->duration() + microsecond;
1166                 erasedRanges->add(startTime.toDouble(), endTime.toDouble());
1167                 trackBuffer.samples.removeSample(samplePair.second.get());
1168             }
1169
1170             for (auto& samplePair : dependentSamples) {
1171                 MediaTime startTime = samplePair.second->presentationTime();
1172                 MediaTime endTime = startTime + samplePair.second->duration() + microsecond;
1173                 erasedRanges->add(startTime.toDouble(), endTime.toDouble());
1174                 trackBuffer.samples.removeSample(samplePair.second.get());
1175             }
1176
1177             erasedRanges->invert();
1178             m_buffered->intersectWith(*erasedRanges.get());
1179         }
1180
1181         // 1.17 If spliced audio frame is set:
1182         // Add spliced audio frame to the track buffer.
1183         // If spliced timed text frame is set:
1184         // Add spliced timed text frame to the track buffer.
1185         // FIXME: Add support for sample splicing.
1186
1187         // Otherwise:
1188         // Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
1189         trackBuffer.samples.addSample(sample);
1190         trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeTimestamp, sample));
1191
1192         // 1.18 Set last decode timestamp for track buffer to decode timestamp.
1193         trackBuffer.lastDecodeTimestamp = decodeTimestamp;
1194
1195         // 1.19 Set last frame duration for track buffer to frame duration.
1196         trackBuffer.lastFrameDuration = frameDuration;
1197
1198         // 1.20 If highest presentation timestamp for track buffer is unset or frame end timestamp is greater
1199         // than highest presentation timestamp, then set highest presentation timestamp for track buffer
1200         // to frame end timestamp.
1201         if (trackBuffer.highestPresentationTimestamp.isInvalid() || frameEndTimestamp > trackBuffer.highestPresentationTimestamp)
1202             trackBuffer.highestPresentationTimestamp = frameEndTimestamp;
1203
1204         // 1.21 If highest presentation end timestamp is unset or frame end timestamp is greater than highest
1205         // presentation end timestamp, then set highest presentation end timestamp equal to frame end timestamp.
1206         if (m_highestPresentationEndTimestamp.isInvalid() || frameEndTimestamp > m_highestPresentationEndTimestamp)
1207             m_highestPresentationEndTimestamp = frameEndTimestamp;
1208
1209         m_buffered->add(presentationTimestamp.toDouble(), (presentationTimestamp + frameDuration + microsecond).toDouble());
1210         m_bufferedSinceLastMonitor += frameDuration.toDouble();
1211
1212         break;
1213     } while (1);
1214
1215     // Steps 2-4 will be handled by MediaSource::monitorSourceBuffers()
1216
1217     // 5. If the media segment contains data beyond the current duration, then run the duration change algorithm with new
1218     // duration set to the maximum of the current duration and the highest end timestamp reported by HTMLMediaElement.buffered.
1219     if (highestPresentationEndTimestamp().toDouble() > m_source->duration())
1220         m_source->setDuration(highestPresentationEndTimestamp().toDouble(), IgnorableExceptionCode());
1221 }
1222
1223 bool SourceBuffer::sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const
1224 {
1225     return m_audioTracks && m_audioTracks->length();
1226 }
1227
1228 bool SourceBuffer::sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const
1229 {
1230     return m_videoTracks && m_videoTracks->length();
1231 }
1232
1233 void SourceBuffer::videoTrackSelectedChanged(VideoTrack* track)
1234 {
1235     // 2.4.5 Changes to selected/enabled track state
1236     // If the selected video track changes, then run the following steps:
1237     // 1. If the SourceBuffer associated with the previously selected video track is not associated with
1238     // any other enabled tracks, run the following steps:
1239     if (track->selected()
1240         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1241         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1242         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1243         // 1.1 Remove the SourceBuffer from activeSourceBuffers.
1244         // 1.2 Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1245         setActive(false);
1246     } else if (!track->selected()) {
1247         // 2. If the SourceBuffer associated with the newly selected video track is not already in activeSourceBuffers,
1248         // run the following steps:
1249         // 2.1 Add the SourceBuffer to activeSourceBuffers.
1250         // 2.2 Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1251         setActive(true);
1252     }
1253
1254     if (!isRemoved())
1255         m_source->mediaElement()->videoTrackSelectedChanged(track);
1256 }
1257
1258 void SourceBuffer::audioTrackEnabledChanged(AudioTrack* track)
1259 {
1260     // 2.4.5 Changes to selected/enabled track state
1261     // If an audio track becomes disabled and the SourceBuffer associated with this track is not
1262     // associated with any other enabled or selected track, then run the following steps:
1263     if (track->enabled()
1264         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1265         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1266         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1267         // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
1268         // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1269         setActive(false);
1270     } else if (!track->enabled()) {
1271         // If an audio track becomes enabled and the SourceBuffer associated with this track is
1272         // not already in activeSourceBuffers, then run the following steps:
1273         // 1. Add the SourceBuffer associated with the audio track to activeSourceBuffers
1274         // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1275         setActive(true);
1276     }
1277
1278     if (!isRemoved())
1279         m_source->mediaElement()->audioTrackEnabledChanged(track);
1280 }
1281
1282 void SourceBuffer::textTrackModeChanged(TextTrack* track)
1283 {
1284     // 2.4.5 Changes to selected/enabled track state
1285     // If a text track mode becomes "disabled" and the SourceBuffer associated with this track is not
1286     // associated with any other enabled or selected track, then run the following steps:
1287     if (track->mode() == TextTrack::disabledKeyword()
1288         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1289         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1290         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1291         // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
1292         // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1293         setActive(false);
1294     } else {
1295         // If a text track mode becomes "showing" or "hidden" and the SourceBuffer associated with this
1296         // track is not already in activeSourceBuffers, then run the following steps:
1297         // 1. Add the SourceBuffer associated with the text track to activeSourceBuffers
1298         // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1299         setActive(true);
1300     }
1301
1302     if (!isRemoved())
1303         m_source->mediaElement()->textTrackModeChanged(track);
1304 }
1305
1306 void SourceBuffer::textTrackAddCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
1307 {
1308     if (!isRemoved())
1309         m_source->mediaElement()->textTrackAddCue(track, cue);
1310 }
1311
1312 void SourceBuffer::textTrackAddCues(TextTrack* track, TextTrackCueList const* cueList)
1313 {
1314     if (!isRemoved())
1315         m_source->mediaElement()->textTrackAddCues(track, cueList);
1316 }
1317
1318 void SourceBuffer::textTrackRemoveCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
1319 {
1320     if (!isRemoved())
1321         m_source->mediaElement()->textTrackRemoveCue(track, cue);
1322 }
1323
1324 void SourceBuffer::textTrackRemoveCues(TextTrack* track, TextTrackCueList const* cueList)
1325 {
1326     if (!isRemoved())
1327         m_source->mediaElement()->textTrackRemoveCues(track, cueList);
1328 }
1329
1330 void SourceBuffer::textTrackKindChanged(TextTrack* track)
1331 {
1332     if (!isRemoved())
1333         m_source->mediaElement()->textTrackKindChanged(track);
1334 }
1335
1336 void SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples(SourceBufferPrivate*, AtomicString trackID)
1337 {
1338     LOG(Media, "SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples(%p)", this);
1339     auto it = m_trackBufferMap.find(trackID);
1340     if (it == m_trackBufferMap.end())
1341         return;
1342
1343     provideMediaData(it->value, trackID);
1344 }
1345
1346 void SourceBuffer::provideMediaData(TrackBuffer& trackBuffer, AtomicString trackID)
1347 {
1348 #if !LOG_DISABLED
1349     unsigned enqueuedSamples = 0;
1350 #endif
1351
1352     auto sampleIt = trackBuffer.decodeQueue.begin();
1353     for (auto sampleEnd = trackBuffer.decodeQueue.end(); sampleIt != sampleEnd; ++sampleIt) {
1354         if (!m_private->isReadyForMoreSamples(trackID)) {
1355             m_private->notifyClientWhenReadyForMoreSamples(trackID);
1356             break;
1357         }
1358
1359         RefPtr<MediaSample> sample = sampleIt->second;
1360         trackBuffer.lastEnqueuedPresentationTime = sample->presentationTime();
1361         m_private->enqueueSample(sample.release(), trackID);
1362 #if !LOG_DISABLED
1363         ++enqueuedSamples;
1364 #endif
1365
1366     }
1367     trackBuffer.decodeQueue.erase(trackBuffer.decodeQueue.begin(), sampleIt);
1368
1369     LOG(Media, "SourceBuffer::provideMediaData(%p) - Enqueued %u samples", this, enqueuedSamples);
1370 }
1371
1372 void SourceBuffer::didDropSample()
1373 {
1374     if (!isRemoved())
1375         m_source->mediaElement()->incrementDroppedFrameCount();
1376 }
1377
1378 void SourceBuffer::monitorBufferingRate()
1379 {
1380     if (!m_bufferedSinceLastMonitor)
1381         return;
1382
1383     double now = monotonicallyIncreasingTime();
1384     double interval = now - m_timeOfBufferingMonitor;
1385     double rateSinceLastMonitor = m_bufferedSinceLastMonitor / interval;
1386
1387     m_timeOfBufferingMonitor = now;
1388     m_bufferedSinceLastMonitor = 0;
1389
1390     m_averageBufferRate = m_averageBufferRate * (1 - ExponentialMovingAverageCoefficient) + rateSinceLastMonitor * ExponentialMovingAverageCoefficient;
1391
1392     LOG(Media, "SourceBuffer::monitorBufferingRate(%p) - m_avegareBufferRate: %lf", this, m_averageBufferRate);
1393 }
1394
1395 bool SourceBuffer::hasCurrentTime() const
1396 {
1397     if (isRemoved() || !m_buffered->length())
1398         return false;
1399
1400     MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
1401     return abs(m_buffered->ranges().nearest(currentTime) - currentTime) <= currentTimeFudgeFactor();
1402 }
1403
1404 bool SourceBuffer::hasFutureTime() const
1405 {
1406     if (isRemoved())
1407         return false;
1408
1409     const PlatformTimeRanges& ranges = m_buffered->ranges();
1410     if (!ranges.length())
1411         return false;
1412
1413     MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
1414     MediaTime nearest = ranges.nearest(currentTime);
1415     if (abs(nearest - currentTime) > currentTimeFudgeFactor())
1416         return false;
1417
1418     size_t found = ranges.find(nearest);
1419     ASSERT(found != notFound);
1420
1421     bool ignoredValid = false;
1422     return ranges.end(found, ignoredValid) - currentTime > currentTimeFudgeFactor();
1423 }
1424
1425 bool SourceBuffer::canPlayThrough()
1426 {
1427     if (isRemoved())
1428         return false;
1429
1430     monitorBufferingRate();
1431
1432     // Assuming no fluctuations in the buffering rate, loading 1 second per second or greater
1433     // means indefinite playback. This could be improved by taking jitter into account.
1434     if (m_averageBufferRate > 1)
1435         return true;
1436
1437     // Add up all the time yet to be buffered.
1438     MediaTime unbufferedTime = MediaTime::zeroTime();
1439     MediaTime currentTime = MediaTime::createWithDouble(m_source->currentTime());
1440     MediaTime duration = MediaTime::createWithDouble(m_source->duration());
1441
1442     PlatformTimeRanges unbufferedRanges = m_buffered->ranges();
1443     unbufferedRanges.invert();
1444     unbufferedRanges.intersectWith(PlatformTimeRanges(currentTime, std::max(currentTime, duration)));
1445     bool valid = true;
1446
1447     for (size_t i = 0, end = unbufferedRanges.length(); i < end; ++i)
1448         unbufferedTime += unbufferedRanges.end(i, valid) - unbufferedRanges.start(i, valid);
1449
1450     MediaTime timeRemaining = duration - currentTime;
1451     return unbufferedTime.toDouble() / m_averageBufferRate < timeRemaining.toDouble();
1452 }
1453
1454 void SourceBuffer::reportExtraMemoryCost()
1455 {
1456     size_t extraMemoryCost = m_pendingAppendData.capacity();
1457     for (auto& trackBuffer : m_trackBufferMap.values())
1458         extraMemoryCost += trackBuffer.samples.sizeInBytes();
1459
1460     if (extraMemoryCost < m_reportedExtraMemoryCost)
1461         return;
1462
1463     size_t extraMemoryCostDelta = extraMemoryCost - m_reportedExtraMemoryCost;
1464     m_reportedExtraMemoryCost = extraMemoryCost;
1465
1466     JSC::JSLockHolder lock(scriptExecutionContext()->vm());
1467     if (extraMemoryCostDelta > 0)
1468         scriptExecutionContext()->vm().heap.reportExtraMemoryCost(extraMemoryCostDelta);
1469 }
1470
1471 Vector<String> SourceBuffer::bufferedSamplesForTrackID(const AtomicString& trackID)
1472 {
1473     auto it = m_trackBufferMap.find(trackID);
1474     if (it == m_trackBufferMap.end())
1475         return Vector<String>();
1476
1477     TrackBuffer& trackBuffer = it->value;
1478     Vector<String> sampleDescriptions;
1479     for (auto& pair : trackBuffer.samples.decodeOrder())
1480         sampleDescriptions.append(toString(*pair.second));
1481
1482     return sampleDescriptions;
1483 }
1484
1485 } // namespace WebCore
1486
1487 #endif