Next batch of conversions to use C++ enum class instead of strings for enumerations
[WebKit-https.git] / Source / WebCore / Modules / mediasource / SourceBuffer.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "SourceBuffer.h"
34
35 #if ENABLE(MEDIA_SOURCE)
36
37 #include "AudioTrackList.h"
38 #include "Event.h"
39 #include "ExceptionCodePlaceholder.h"
40 #include "GenericEventQueue.h"
41 #include "HTMLMediaElement.h"
42 #include "InbandTextTrack.h"
43 #include "Logging.h"
44 #include "MediaDescription.h"
45 #include "MediaSample.h"
46 #include "MediaSource.h"
47 #include "SampleMap.h"
48 #include "SourceBufferPrivate.h"
49 #include "TextTrackList.h"
50 #include "TimeRanges.h"
51 #include "VideoTrackList.h"
52 #include <limits>
53 #include <map>
54 #include <runtime/JSCInlines.h>
55 #include <runtime/JSLock.h>
56 #include <runtime/VM.h>
57 #include <wtf/CurrentTime.h>
58 #include <wtf/NeverDestroyed.h>
59 #if !LOG_DISABLED
60 #include <wtf/text/StringBuilder.h>
61 #endif
62
63 namespace WebCore {
64
65 static const double ExponentialMovingAverageCoefficient = 0.1;
66
67 // Allow hasCurrentTime() to be off by as much as the length of a 24fps video frame
68 static const MediaTime& currentTimeFudgeFactor()
69 {
70     static NeverDestroyed<MediaTime> fudgeFactor(1, 24);
71     return fudgeFactor;
72 }
73
74 struct SourceBuffer::TrackBuffer {
75     MediaTime lastDecodeTimestamp;
76     MediaTime lastFrameDuration;
77     MediaTime highestPresentationTimestamp;
78     MediaTime lastEnqueuedPresentationTime;
79     MediaTime lastEnqueuedDecodeEndTime;
80     bool needRandomAccessFlag { true };
81     bool enabled { false };
82     bool needsReenqueueing { false };
83     SampleMap samples;
84     DecodeOrderSampleMap::MapType decodeQueue;
85     RefPtr<MediaDescription> description;
86
87     TrackBuffer()
88         : lastDecodeTimestamp(MediaTime::invalidTime())
89         , lastFrameDuration(MediaTime::invalidTime())
90         , highestPresentationTimestamp(MediaTime::invalidTime())
91         , lastEnqueuedPresentationTime(MediaTime::invalidTime())
92         , lastEnqueuedDecodeEndTime(MediaTime::invalidTime())
93     {
94     }
95 };
96
97 Ref<SourceBuffer> SourceBuffer::create(Ref<SourceBufferPrivate>&& sourceBufferPrivate, MediaSource* source)
98 {
99     auto sourceBuffer = adoptRef(*new SourceBuffer(WTFMove(sourceBufferPrivate), source));
100     sourceBuffer->suspendIfNeeded();
101     return sourceBuffer;
102 }
103
104 SourceBuffer::SourceBuffer(Ref<SourceBufferPrivate>&& sourceBufferPrivate, MediaSource* source)
105     : ActiveDOMObject(source->scriptExecutionContext())
106     , m_private(WTFMove(sourceBufferPrivate))
107     , m_source(source)
108     , m_asyncEventQueue(*this)
109     , m_appendBufferTimer(*this, &SourceBuffer::appendBufferTimerFired)
110     , m_appendWindowStart(MediaTime::zeroTime())
111     , m_appendWindowEnd(MediaTime::positiveInfiniteTime())
112     , m_groupStartTimestamp(MediaTime::invalidTime())
113     , m_groupEndTimestamp(MediaTime::zeroTime())
114     , m_buffered(TimeRanges::create())
115     , m_appendState(WaitingForSegment)
116     , m_timeOfBufferingMonitor(monotonicallyIncreasingTime())
117     , m_pendingRemoveStart(MediaTime::invalidTime())
118     , m_pendingRemoveEnd(MediaTime::invalidTime())
119     , m_removeTimer(*this, &SourceBuffer::removeTimerFired)
120 {
121     ASSERT(m_source);
122
123     m_private->setClient(this);
124 }
125
126 SourceBuffer::~SourceBuffer()
127 {
128     ASSERT(isRemoved());
129
130     m_private->setClient(nullptr);
131 }
132
133 PassRefPtr<TimeRanges> SourceBuffer::buffered(ExceptionCode& ec) const
134 {
135     // Section 3.1 buffered attribute steps.
136     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#attributes-1
137     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
138     //    INVALID_STATE_ERR exception and abort these steps.
139     if (isRemoved()) {
140         ec = INVALID_STATE_ERR;
141         return nullptr;
142     }
143
144     // 2. Return a new static normalized TimeRanges object for the media segments buffered.
145     return m_buffered->copy();
146 }
147
148 const RefPtr<TimeRanges>& SourceBuffer::buffered() const
149 {
150     return m_buffered;
151 }
152
153 double SourceBuffer::timestampOffset() const
154 {
155     return m_timestampOffset.toDouble();
156 }
157
158 void SourceBuffer::setTimestampOffset(double offset, ExceptionCode& ec)
159 {
160     // Section 3.1 timestampOffset attribute setter steps.
161     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#attributes-1
162     // 1. Let new timestamp offset equal the new value being assigned to this attribute.
163     // 2. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw an
164     //    INVALID_STATE_ERR exception and abort these steps.
165     // 3. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
166     if (isRemoved() || m_updating) {
167         ec = INVALID_STATE_ERR;
168         return;
169     }
170
171     // 4. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
172     // 4.1 Set the readyState attribute of the parent media source to "open"
173     // 4.2 Queue a task to fire a simple event named sourceopen at the parent media source.
174     m_source->openIfInEndedState();
175
176     // 5. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
177     if (m_appendState == ParsingMediaSegment) {
178         ec = INVALID_STATE_ERR;
179         return;
180     }
181
182     MediaTime newTimestampOffset = MediaTime::createWithDouble(offset);
183
184     // 6. If the mode attribute equals "sequence", then set the group start timestamp to new timestamp offset.
185     if (m_mode == AppendMode::Sequence)
186         m_groupStartTimestamp = newTimestampOffset;
187
188     // 7. Update the attribute to the new value.
189     m_timestampOffset = newTimestampOffset;
190 }
191
192 double SourceBuffer::appendWindowStart() const
193 {
194     return m_appendWindowStart.toDouble();
195 };
196
197 void SourceBuffer::setAppendWindowStart(double newValue, ExceptionCode& ec)
198 {
199     // Section 3.1 appendWindowStart attribute setter steps.
200     // http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendWindowStart
201     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source,
202     //    then throw an INVALID_STATE_ERR exception and abort these steps.
203     // 2. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
204     if (isRemoved() || m_updating) {
205         ec = INVALID_STATE_ERR;
206         return;
207     }
208
209     // 3. If the new value is less than 0 or greater than or equal to appendWindowEnd then
210     //    throw an INVALID_ACCESS_ERR exception and abort these steps.
211     if (newValue < 0 || newValue >= m_appendWindowEnd.toDouble()) {
212         ec = INVALID_ACCESS_ERR;
213         return;
214     }
215
216     // 4. Update the attribute to the new value.
217     m_appendWindowStart = MediaTime::createWithDouble(newValue);
218 }
219
220 double SourceBuffer::appendWindowEnd() const
221 {
222     return m_appendWindowEnd.toDouble();
223 };
224
225 void SourceBuffer::setAppendWindowEnd(double newValue, ExceptionCode& ec)
226 {
227     // Section 3.1 appendWindowEnd attribute setter steps.
228     // http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendWindowEnd
229     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source,
230     //    then throw an INVALID_STATE_ERR exception and abort these steps.
231     // 2. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
232     if (isRemoved() || m_updating) {
233         ec = INVALID_STATE_ERR;
234         return;
235     }
236
237     // 3. If the new value equals NaN, then throw an INVALID_ACCESS_ERR and abort these steps.
238     // 4. If the new value is less than or equal to appendWindowStart then throw an INVALID_ACCESS_ERR exception
239     //    and abort these steps.
240     if (std::isnan(newValue) || newValue <= m_appendWindowStart.toDouble()) {
241         ec = INVALID_ACCESS_ERR;
242         return;
243     }
244
245     // 5.. Update the attribute to the new value.
246     m_appendWindowEnd = MediaTime::createWithDouble(newValue);
247 }
248
249
250 void SourceBuffer::appendBuffer(ArrayBuffer& data, ExceptionCode& ec)
251 {
252     appendBufferInternal(static_cast<unsigned char*>(data.data()), data.byteLength(), ec);
253 }
254
255 void SourceBuffer::appendBuffer(ArrayBufferView* data, ExceptionCode& ec)
256 {
257     if (!data) {
258         ec = TypeError;
259         return;
260     }
261
262     appendBufferInternal(static_cast<unsigned char*>(data->baseAddress()), data->byteLength(), ec);
263 }
264
265 void SourceBuffer::resetParserState()
266 {
267     // Section 3.5.2 Reset Parser State algorithm steps.
268     // http://www.w3.org/TR/2014/CR-media-source-20140717/#sourcebuffer-reset-parser-state
269     // 1. If the append state equals PARSING_MEDIA_SEGMENT and the input buffer contains some complete coded frames,
270     //    then run the coded frame processing algorithm until all of these complete coded frames have been processed.
271     // FIXME: If any implementation will work in pulling mode (instead of async push to SourceBufferPrivate, and forget)
272     //     this should be handled somehow either here, or in m_private->abort();
273
274     // 2. Unset the last decode timestamp on all track buffers.
275     // 3. Unset the last frame duration on all track buffers.
276     // 4. Unset the highest presentation timestamp on all track buffers.
277     // 5. Set the need random access point flag on all track buffers to true.
278     for (auto& trackBufferPair : m_trackBufferMap.values()) {
279         trackBufferPair.lastDecodeTimestamp = MediaTime::invalidTime();
280         trackBufferPair.lastFrameDuration = MediaTime::invalidTime();
281         trackBufferPair.highestPresentationTimestamp = MediaTime::invalidTime();
282         trackBufferPair.needRandomAccessFlag = true;
283     }
284     // 6. Remove all bytes from the input buffer.
285     // Note: this is handled by abortIfUpdating()
286     // 7. Set append state to WAITING_FOR_SEGMENT.
287     m_appendState = WaitingForSegment;
288
289     m_private->abort();
290 }
291
292 void SourceBuffer::abort(ExceptionCode& ec)
293 {
294     // Section 3.2 abort() method steps.
295     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void
296     // 1. If this object has been removed from the sourceBuffers attribute of the parent media source
297     //    then throw an INVALID_STATE_ERR exception and abort these steps.
298     // 2. If the readyState attribute of the parent media source is not in the "open" state
299     //    then throw an INVALID_STATE_ERR exception and abort these steps.
300     if (isRemoved() || !m_source->isOpen()) {
301         ec = INVALID_STATE_ERR;
302         return;
303     }
304
305     // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ...
306     abortIfUpdating();
307
308     // 4. Run the reset parser state algorithm.
309     resetParserState();
310
311     // 5. Set appendWindowStart to the presentation start time.
312     m_appendWindowStart = MediaTime::zeroTime();
313
314     // 6. Set appendWindowEnd to positive Infinity.
315     m_appendWindowEnd = MediaTime::positiveInfiniteTime();
316 }
317
318 void SourceBuffer::remove(double start, double end, ExceptionCode& ec)
319 {
320     remove(MediaTime::createWithDouble(start), MediaTime::createWithDouble(end), ec);
321 }
322
323 void SourceBuffer::remove(const MediaTime& start, const MediaTime& end, ExceptionCode& ec)
324 {
325     LOG(MediaSource, "SourceBuffer::remove(%p) - start(%lf), end(%lf)", this, start.toDouble(), end.toDouble());
326
327     // Section 3.2 remove() method steps.
328     // 1. If duration equals NaN, then throw an InvalidAccessError exception and abort these steps.
329     // 2. If start is negative or greater than duration, then throw an InvalidAccessError exception and abort these steps.
330     // 3. If end is less than or equal to start, then throw an InvalidAccessError exception and abort these steps.
331
332     // FIXME: reorder/revisit this section once <https://www.w3.org/Bugs/Public/show_bug.cgi?id=27857> got resolved
333     // as it seems wrong to check mediaSource duration before checking isRemoved().
334     if ((m_source && m_source->duration().isInvalid())
335         || start < MediaTime::zeroTime() || (m_source && start > m_source->duration())
336         || end <= start) {
337         ec = INVALID_ACCESS_ERR;
338         return;
339     }
340
341     // 4. If this object has been removed from the sourceBuffers attribute of the parent media source then throw an
342     //    InvalidStateError exception and abort these steps.
343     // 5. If the updating attribute equals true, then throw an InvalidStateError exception and abort these steps.
344     if (isRemoved() || m_updating) {
345         ec = INVALID_STATE_ERR;
346         return;
347     }
348
349     // 6. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
350     // 6.1. Set the readyState attribute of the parent media source to "open"
351     // 6.2. Queue a task to fire a simple event named sourceopen at the parent media source .
352     m_source->openIfInEndedState();
353
354     // 7. Run the range removal algorithm with start and end as the start and end of the removal range.
355     rangeRemoval(start, end);
356 }
357
358 void SourceBuffer::rangeRemoval(const MediaTime& start, const MediaTime& end)
359 {
360     // 3.5.7 Range Removal
361     // https://rawgit.com/w3c/media-source/7bbe4aa33c61ec025bc7acbd80354110f6a000f9/media-source.html#sourcebuffer-range-removal
362     // 1. Let start equal the starting presentation timestamp for the removal range.
363     // 2. Let end equal the end presentation timestamp for the removal range.
364     // 3. Set the updating attribute to true.
365     m_updating = true;
366
367     // 4. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
368     scheduleEvent(eventNames().updatestartEvent);
369
370     // 5. Return control to the caller and run the rest of the steps asynchronously.
371     m_pendingRemoveStart = start;
372     m_pendingRemoveEnd = end;
373     m_removeTimer.startOneShot(0);
374 }
375
376 void SourceBuffer::abortIfUpdating()
377 {
378     // Section 3.2 abort() method step 3 substeps.
379     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-abort-void
380
381     if (!m_updating)
382         return;
383
384     // 3.1. Abort the buffer append and stream append loop algorithms if they are running.
385     m_appendBufferTimer.stop();
386     m_pendingAppendData.clear();
387
388     m_removeTimer.stop();
389     m_pendingRemoveStart = MediaTime::invalidTime();
390     m_pendingRemoveEnd = MediaTime::invalidTime();
391
392     // 3.2. Set the updating attribute to false.
393     m_updating = false;
394
395     // 3.3. Queue a task to fire a simple event named abort at this SourceBuffer object.
396     scheduleEvent(eventNames().abortEvent);
397
398     // 3.4. Queue a task to fire a simple event named updateend at this SourceBuffer object.
399     scheduleEvent(eventNames().updateendEvent);
400 }
401
402 void SourceBuffer::removedFromMediaSource()
403 {
404     if (isRemoved())
405         return;
406
407     abortIfUpdating();
408
409     for (auto& trackBufferPair : m_trackBufferMap.values()) {
410         trackBufferPair.samples.clear();
411         trackBufferPair.decodeQueue.clear();
412     }
413
414     m_private->removedFromMediaSource();
415     m_source = nullptr;
416 }
417
418 void SourceBuffer::seekToTime(const MediaTime& time)
419 {
420     LOG(MediaSource, "SourceBuffer::seekToTime(%p) - time(%s)", this, toString(time).utf8().data());
421
422     for (auto& trackBufferPair : m_trackBufferMap) {
423         TrackBuffer& trackBuffer = trackBufferPair.value;
424         const AtomicString& trackID = trackBufferPair.key;
425
426         trackBuffer.needsReenqueueing = true;
427         reenqueueMediaForTime(trackBuffer, trackID, time);
428     }
429 }
430
431 MediaTime SourceBuffer::sourceBufferPrivateFastSeekTimeForMediaTime(SourceBufferPrivate*, const MediaTime& targetTime, const MediaTime& negativeThreshold, const MediaTime& positiveThreshold)
432 {
433     MediaTime seekTime = targetTime;
434     MediaTime lowerBoundTime = targetTime - negativeThreshold;
435     MediaTime upperBoundTime = targetTime + positiveThreshold;
436
437     for (auto& trackBuffer : m_trackBufferMap.values()) {
438         // Find the sample which contains the target time time.
439         auto futureSyncSampleIterator = trackBuffer.samples.decodeOrder().findSyncSampleAfterPresentationTime(targetTime, positiveThreshold);
440         auto pastSyncSampleIterator = trackBuffer.samples.decodeOrder().findSyncSamplePriorToPresentationTime(targetTime, negativeThreshold);
441         auto upperBound = trackBuffer.samples.decodeOrder().end();
442         auto lowerBound = trackBuffer.samples.decodeOrder().rend();
443
444         if (futureSyncSampleIterator == upperBound && pastSyncSampleIterator == lowerBound)
445             continue;
446
447         MediaTime futureSeekTime = MediaTime::positiveInfiniteTime();
448         if (futureSyncSampleIterator != upperBound) {
449             RefPtr<MediaSample>& sample = futureSyncSampleIterator->second;
450             futureSeekTime = sample->presentationTime();
451         }
452
453         MediaTime pastSeekTime = MediaTime::negativeInfiniteTime();
454         if (pastSyncSampleIterator != lowerBound) {
455             RefPtr<MediaSample>& sample = pastSyncSampleIterator->second;
456             pastSeekTime = sample->presentationTime();
457         }
458
459         MediaTime trackSeekTime = abs(targetTime - futureSeekTime) < abs(targetTime - pastSeekTime) ? futureSeekTime : pastSeekTime;
460         if (abs(targetTime - trackSeekTime) > abs(targetTime - seekTime))
461             seekTime = trackSeekTime;
462     }
463
464     return seekTime;
465 }
466
467 bool SourceBuffer::hasPendingActivity() const
468 {
469     return m_source || m_asyncEventQueue.hasPendingEvents();
470 }
471
472 void SourceBuffer::stop()
473 {
474     m_appendBufferTimer.stop();
475     m_removeTimer.stop();
476 }
477
478 bool SourceBuffer::canSuspendForDocumentSuspension() const
479 {
480     return !hasPendingActivity();
481 }
482
483 const char* SourceBuffer::activeDOMObjectName() const
484 {
485     return "SourceBuffer";
486 }
487
488 bool SourceBuffer::isRemoved() const
489 {
490     return !m_source;
491 }
492
493 void SourceBuffer::scheduleEvent(const AtomicString& eventName)
494 {
495     RefPtr<Event> event = Event::create(eventName, false, false);
496     event->setTarget(this);
497
498     m_asyncEventQueue.enqueueEvent(event.release());
499 }
500
501 void SourceBuffer::appendBufferInternal(unsigned char* data, unsigned size, ExceptionCode& ec)
502 {
503     // Section 3.2 appendBuffer()
504     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#widl-SourceBuffer-appendBuffer-void-ArrayBufferView-data
505
506     // Step 1 is enforced by the caller.
507     // 2. Run the prepare append algorithm.
508     // Section 3.5.4 Prepare AppendAlgorithm
509
510     // 1. If the SourceBuffer has been removed from the sourceBuffers attribute of the parent media source
511     // then throw an INVALID_STATE_ERR exception and abort these steps.
512     // 2. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
513     if (isRemoved() || m_updating) {
514         ec = INVALID_STATE_ERR;
515         return;
516     }
517
518     // 3. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
519     // 3.1. Set the readyState attribute of the parent media source to "open"
520     // 3.2. Queue a task to fire a simple event named sourceopen at the parent media source .
521     m_source->openIfInEndedState();
522
523     // 4. Run the coded frame eviction algorithm.
524     evictCodedFrames(size);
525
526     // FIXME: enable this code when MSE libraries have been updated to support it.
527 #if 0
528     // 5. If the buffer full flag equals true, then throw a QUOTA_EXCEEDED_ERR exception and abort these step.
529     if (m_bufferFull) {
530         LOG(MediaSource, "SourceBuffer::appendBufferInternal(%p) -  buffer full, failing with QUOTA_EXCEEDED_ERR error", this);
531         ec = QUOTA_EXCEEDED_ERR;
532         return;
533     }
534 #endif
535
536     // NOTE: Return to 3.2 appendBuffer()
537     // 3. Add data to the end of the input buffer.
538     m_pendingAppendData.append(data, size);
539
540     // 4. Set the updating attribute to true.
541     m_updating = true;
542
543     // 5. Queue a task to fire a simple event named updatestart at this SourceBuffer object.
544     scheduleEvent(eventNames().updatestartEvent);
545
546     // 6. Asynchronously run the buffer append algorithm.
547     m_appendBufferTimer.startOneShot(0);
548
549     reportExtraMemoryAllocated();
550 }
551
552 void SourceBuffer::appendBufferTimerFired()
553 {
554     if (isRemoved())
555         return;
556
557     ASSERT(m_updating);
558
559     // Section 3.5.5 Buffer Append Algorithm
560     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
561
562     // 1. Run the segment parser loop algorithm.
563     size_t appendSize = m_pendingAppendData.size();
564     if (!appendSize) {
565         // Resize buffer for 0 byte appends so we always have a valid pointer.
566         // We need to convey all appends, even 0 byte ones to |m_private| so
567         // that it can clear its end of stream state if necessary.
568         m_pendingAppendData.resize(1);
569     }
570
571     // Section 3.5.1 Segment Parser Loop
572     // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebuffer-segment-parser-loop
573     // When the segment parser loop algorithm is invoked, run the following steps:
574
575     // 1. Loop Top: If the input buffer is empty, then jump to the need more data step below.
576     if (!m_pendingAppendData.size()) {
577         sourceBufferPrivateAppendComplete(&m_private.get(), AppendSucceeded);
578         return;
579     }
580
581     m_private->append(m_pendingAppendData.data(), appendSize);
582     m_pendingAppendData.clear();
583 }
584
585 void SourceBuffer::sourceBufferPrivateAppendComplete(SourceBufferPrivate*, AppendResult result)
586 {
587     if (isRemoved())
588         return;
589
590     // Section 3.5.5 Buffer Append Algorithm, ctd.
591     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
592
593     // 2. If the input buffer contains bytes that violate the SourceBuffer byte stream format specification,
594     // then run the append error algorithm with the decode error parameter set to true and abort this algorithm.
595     if (result == ParsingFailed) {
596         LOG(MediaSource, "SourceBuffer::sourceBufferPrivateAppendComplete(%p) - result = ParsingFailed", this);
597         appendError(true);
598         return;
599     }
600
601     // NOTE: Steps 3 - 6 enforced by sourceBufferPrivateDidReceiveInitializationSegment() and
602     // sourceBufferPrivateDidReceiveSample below.
603
604     // 7. Need more data: Return control to the calling algorithm.
605
606     // NOTE: return to Section 3.5.5
607     // 2.If the segment parser loop algorithm in the previous step was aborted, then abort this algorithm.
608     if (result != AppendSucceeded)
609         return;
610
611     // 3. Set the updating attribute to false.
612     m_updating = false;
613
614     // 4. Queue a task to fire a simple event named update at this SourceBuffer object.
615     scheduleEvent(eventNames().updateEvent);
616
617     // 5. Queue a task to fire a simple event named updateend at this SourceBuffer object.
618     scheduleEvent(eventNames().updateendEvent);
619
620     if (m_source)
621         m_source->monitorSourceBuffers();
622
623     MediaTime currentMediaTime = m_source->currentTime();
624     for (auto& trackBufferPair : m_trackBufferMap) {
625         TrackBuffer& trackBuffer = trackBufferPair.value;
626         const AtomicString& trackID = trackBufferPair.key;
627
628         if (trackBuffer.needsReenqueueing) {
629             LOG(MediaSource, "SourceBuffer::sourceBufferPrivateAppendComplete(%p) - reenqueuing at time (%s)", this, toString(currentMediaTime).utf8().data());
630             reenqueueMediaForTime(trackBuffer, trackID, currentMediaTime);
631         } else
632             provideMediaData(trackBuffer, trackID);
633     }
634
635     reportExtraMemoryAllocated();
636     if (extraMemoryCost() > this->maximumBufferSize())
637         m_bufferFull = true;
638
639     LOG(Media, "SourceBuffer::sourceBufferPrivateAppendComplete(%p) - buffered = %s", this, toString(m_buffered->ranges()).utf8().data());
640 }
641
642 void SourceBuffer::sourceBufferPrivateDidReceiveRenderingError(SourceBufferPrivate*, int error)
643 {
644 #if LOG_DISABLED
645     UNUSED_PARAM(error);
646 #endif
647
648     LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidReceiveRenderingError(%p) - result = %i", this, error);
649
650     if (!isRemoved())
651         m_source->streamEndedWithError(EndOfStreamError::Decode);
652 }
653
654 static bool decodeTimeComparator(const PresentationOrderSampleMap::MapType::value_type& a, const PresentationOrderSampleMap::MapType::value_type& b)
655 {
656     return a.second->decodeTime() < b.second->decodeTime();
657 }
658
659 static PassRefPtr<TimeRanges> removeSamplesFromTrackBuffer(const DecodeOrderSampleMap::MapType& samples, SourceBuffer::TrackBuffer& trackBuffer, const SourceBuffer* buffer, const char* logPrefix)
660 {
661 #if !LOG_DISABLED
662     double earliestSample = std::numeric_limits<double>::infinity();
663     double latestSample = 0;
664     size_t bytesRemoved = 0;
665 #else
666     UNUSED_PARAM(logPrefix);
667     UNUSED_PARAM(buffer);
668 #endif
669
670     RefPtr<TimeRanges> erasedRanges = TimeRanges::create();
671     MediaTime microsecond(1, 1000000);
672     for (auto sampleIt : samples) {
673         const DecodeOrderSampleMap::KeyType& decodeKey = sampleIt.first;
674 #if !LOG_DISABLED
675         size_t startBufferSize = trackBuffer.samples.sizeInBytes();
676 #endif
677
678         RefPtr<MediaSample>& sample = sampleIt.second;
679         LOG(MediaSource, "SourceBuffer::%s(%p) - removing sample(%s)", logPrefix, buffer, toString(*sampleIt.second).utf8().data());
680
681         // Remove the erased samples from the TrackBuffer sample map.
682         trackBuffer.samples.removeSample(sample.get());
683
684         // Also remove the erased samples from the TrackBuffer decodeQueue.
685         trackBuffer.decodeQueue.erase(decodeKey);
686
687         double startTime = sample->presentationTime().toDouble();
688         double endTime = startTime + (sample->duration() + microsecond).toDouble();
689         erasedRanges->add(startTime, endTime);
690
691 #if !LOG_DISABLED
692         bytesRemoved += startBufferSize - trackBuffer.samples.sizeInBytes();
693         if (startTime < earliestSample)
694             earliestSample = startTime;
695         if (endTime > latestSample)
696             latestSample = endTime;
697 #endif
698     }
699
700 #if !LOG_DISABLED
701     if (bytesRemoved)
702         LOG(MediaSource, "SourceBuffer::%s(%p) removed %zu bytes, start(%lf), end(%lf)", logPrefix, buffer, bytesRemoved, earliestSample, latestSample);
703 #endif
704
705     return erasedRanges.release();
706 }
707
708 void SourceBuffer::removeCodedFrames(const MediaTime& start, const MediaTime& end)
709 {
710     LOG(MediaSource, "SourceBuffer::removeCodedFrames(%p) - start(%s), end(%s)", this, toString(start).utf8().data(), toString(end).utf8().data());
711
712     // 3.5.9 Coded Frame Removal Algorithm
713     // https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebuffer-coded-frame-removal
714
715     // 1. Let start be the starting presentation timestamp for the removal range.
716     MediaTime durationMediaTime = m_source->duration();
717     MediaTime currentMediaTime = m_source->currentTime();
718
719     // 2. Let end be the end presentation timestamp for the removal range.
720     // 3. For each track buffer in this source buffer, run the following steps:
721     for (auto& iter : m_trackBufferMap) {
722         TrackBuffer& trackBuffer = iter.value;
723
724         // 3.1. Let remove end timestamp be the current value of duration
725         // 3.2 If this track buffer has a random access point timestamp that is greater than or equal to end, then update
726         // remove end timestamp to that random access point timestamp.
727         // NOTE: findSyncSampleAfterPresentationTime will return the next sync sample on or after the presentation time
728         // or decodeOrder().end() if no sync sample exists after that presentation time.
729         DecodeOrderSampleMap::iterator removeDecodeEnd = trackBuffer.samples.decodeOrder().findSyncSampleAfterPresentationTime(end);
730         PresentationOrderSampleMap::iterator removePresentationEnd;
731         if (removeDecodeEnd == trackBuffer.samples.decodeOrder().end())
732             removePresentationEnd = trackBuffer.samples.presentationOrder().end();
733         else
734             removePresentationEnd = trackBuffer.samples.presentationOrder().findSampleWithPresentationTime(removeDecodeEnd->second->presentationTime());
735
736         PresentationOrderSampleMap::iterator removePresentationStart = trackBuffer.samples.presentationOrder().findSampleOnOrAfterPresentationTime(start);
737         if (removePresentationStart == removePresentationEnd)
738             continue;
739
740         // 3.3 Remove all media data, from this track buffer, that contain starting timestamps greater than or equal to
741         // start and less than the remove end timestamp.
742         // NOTE: frames must be removed in decode order, so that all dependant frames between the frame to be removed
743         // and the next sync sample frame are removed. But we must start from the first sample in decode order, not
744         // presentation order.
745         PresentationOrderSampleMap::iterator minDecodeTimeIter = std::min_element(removePresentationStart, removePresentationEnd, decodeTimeComparator);
746         DecodeOrderSampleMap::KeyType decodeKey(minDecodeTimeIter->second->decodeTime(), minDecodeTimeIter->second->presentationTime());
747         DecodeOrderSampleMap::iterator removeDecodeStart = trackBuffer.samples.decodeOrder().findSampleWithDecodeKey(decodeKey);
748
749         DecodeOrderSampleMap::MapType erasedSamples(removeDecodeStart, removeDecodeEnd);
750         RefPtr<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(erasedSamples, trackBuffer, this, "removeCodedFrames");
751
752         // Only force the TrackBuffer to re-enqueue if the removed ranges overlap with enqueued and possibly
753         // not yet displayed samples.
754         if (currentMediaTime < trackBuffer.lastEnqueuedPresentationTime) {
755             PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
756             possiblyEnqueuedRanges.intersectWith(erasedRanges->ranges());
757             if (possiblyEnqueuedRanges.length())
758                 trackBuffer.needsReenqueueing = true;
759         }
760
761         erasedRanges->invert();
762         m_buffered->intersectWith(*erasedRanges);
763         setBufferedDirty(true);
764
765         // 3.4 If this object is in activeSourceBuffers, the current playback position is greater than or equal to start
766         // and less than the remove end timestamp, and HTMLMediaElement.readyState is greater than HAVE_METADATA, then set
767         // the HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback.
768         if (m_active && currentMediaTime >= start && currentMediaTime < end && m_private->readyState() > MediaPlayer::HaveMetadata)
769             m_private->setReadyState(MediaPlayer::HaveMetadata);
770     }
771
772     // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
773     // No-op
774
775     LOG(Media, "SourceBuffer::removeCodedFrames(%p) - buffered = %s", this, toString(m_buffered->ranges()).utf8().data());
776 }
777
778 void SourceBuffer::removeTimerFired()
779 {
780     ASSERT(m_updating);
781     ASSERT(m_pendingRemoveStart.isValid());
782     ASSERT(m_pendingRemoveStart < m_pendingRemoveEnd);
783
784     // Section 3.5.7 Range Removal
785     // http://w3c.github.io/media-source/#sourcebuffer-range-removal
786
787     // 6. Run the coded frame removal algorithm with start and end as the start and end of the removal range.
788     removeCodedFrames(m_pendingRemoveStart, m_pendingRemoveEnd);
789
790     // 7. Set the updating attribute to false.
791     m_updating = false;
792     m_pendingRemoveStart = MediaTime::invalidTime();
793     m_pendingRemoveEnd = MediaTime::invalidTime();
794
795     // 8. Queue a task to fire a simple event named update at this SourceBuffer object.
796     scheduleEvent(eventNames().updateEvent);
797
798     // 9. Queue a task to fire a simple event named updateend at this SourceBuffer object.
799     scheduleEvent(eventNames().updateendEvent);
800 }
801
802 void SourceBuffer::evictCodedFrames(size_t newDataSize)
803 {
804     // 3.5.13 Coded Frame Eviction Algorithm
805     // http://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-eviction
806
807     if (isRemoved())
808         return;
809
810     // This algorithm is run to free up space in this source buffer when new data is appended.
811     // 1. Let new data equal the data that is about to be appended to this SourceBuffer.
812     // 2. If the buffer full flag equals false, then abort these steps.
813     if (!m_bufferFull)
814         return;
815
816     size_t maximumBufferSize = this->maximumBufferSize();
817
818     // 3. Let removal ranges equal a list of presentation time ranges that can be evicted from
819     // the presentation to make room for the new data.
820
821     // NOTE: begin by removing data from the beginning of the buffered ranges, 30 seconds at
822     // a time, up to 30 seconds before currentTime.
823     MediaTime thirtySeconds = MediaTime(30, 1);
824     MediaTime currentTime = m_source->currentTime();
825     MediaTime maximumRangeEnd = currentTime - thirtySeconds;
826
827 #if !LOG_DISABLED
828     LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - currentTime = %lf, require %zu bytes, maximum buffer size is %zu", this, m_source->currentTime().toDouble(), extraMemoryCost() + newDataSize, maximumBufferSize);
829     size_t initialBufferedSize = extraMemoryCost();
830 #endif
831
832     MediaTime rangeStart = MediaTime::zeroTime();
833     MediaTime rangeEnd = rangeStart + thirtySeconds;
834     while (rangeStart < maximumRangeEnd) {
835         // 4. For each range in removal ranges, run the coded frame removal algorithm with start and
836         // end equal to the removal range start and end timestamp respectively.
837         removeCodedFrames(rangeStart, std::min(rangeEnd, maximumRangeEnd));
838         if (extraMemoryCost() + newDataSize < maximumBufferSize) {
839             m_bufferFull = false;
840             break;
841         }
842
843         rangeStart += thirtySeconds;
844         rangeEnd += thirtySeconds;
845     }
846
847     if (!m_bufferFull) {
848         LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes", this, initialBufferedSize - extraMemoryCost());
849         return;
850     }
851
852     // If there still isn't enough free space and there buffers in time ranges after the current range (ie. there is a gap after
853     // the current buffered range), delete 30 seconds at a time from duration back to the current time range or 30 seconds after
854     // currenTime whichever we hit first.
855     auto buffered = m_buffered->ranges();
856     size_t currentTimeRange = buffered.find(currentTime);
857     if (currentTimeRange == notFound || currentTimeRange == buffered.length() - 1) {
858         LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes but FAILED to free enough", this, initialBufferedSize - extraMemoryCost());
859         return;
860     }
861
862     MediaTime minimumRangeStart = currentTime + thirtySeconds;
863
864     rangeEnd = m_source->duration();
865     rangeStart = rangeEnd - thirtySeconds;
866     while (rangeStart > minimumRangeStart) {
867
868         // Do not evict data from the time range that contains currentTime.
869         size_t startTimeRange = buffered.find(rangeStart);
870         if (startTimeRange == currentTimeRange) {
871             size_t endTimeRange = buffered.find(rangeEnd);
872             if (endTimeRange == currentTimeRange)
873                 break;
874
875             rangeEnd = buffered.start(endTimeRange);
876         }
877
878         // 4. For each range in removal ranges, run the coded frame removal algorithm with start and
879         // end equal to the removal range start and end timestamp respectively.
880         removeCodedFrames(std::max(minimumRangeStart, rangeStart), rangeEnd);
881         if (extraMemoryCost() + newDataSize < maximumBufferSize) {
882             m_bufferFull = false;
883             break;
884         }
885
886         rangeStart -= thirtySeconds;
887         rangeEnd -= thirtySeconds;
888     }
889
890     LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes%s", this, initialBufferedSize - extraMemoryCost(), m_bufferFull ? "" : " but FAILED to free enough");
891 }
892
893 size_t SourceBuffer::maximumBufferSize() const
894 {
895     if (isRemoved())
896         return 0;
897
898     HTMLMediaElement* element = m_source->mediaElement();
899     if (!element)
900         return 0;
901
902     return element->maximumSourceBufferSize(*this);
903 }
904
905 VideoTrackList* SourceBuffer::videoTracks()
906 {
907     if (!m_source || !m_source->mediaElement())
908         return nullptr;
909
910     if (!m_videoTracks)
911         m_videoTracks = VideoTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
912
913     return m_videoTracks.get();
914 }
915
916 AudioTrackList* SourceBuffer::audioTracks()
917 {
918     if (!m_source || !m_source->mediaElement())
919         return nullptr;
920
921     if (!m_audioTracks)
922         m_audioTracks = AudioTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
923
924     return m_audioTracks.get();
925 }
926
927 TextTrackList* SourceBuffer::textTracks()
928 {
929     if (!m_source || !m_source->mediaElement())
930         return nullptr;
931
932     if (!m_textTracks)
933         m_textTracks = TextTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
934
935     return m_textTracks.get();
936 }
937
938 void SourceBuffer::setActive(bool active)
939 {
940     if (m_active == active)
941         return;
942
943     m_active = active;
944     m_private->setActive(active);
945     if (!isRemoved())
946         m_source->sourceBufferDidChangeActiveState(*this, active);
947 }
948
949 void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment& segment)
950 {
951     if (isRemoved())
952         return;
953
954     LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(%p)", this);
955
956     // 3.5.8 Initialization Segment Received (ctd)
957     // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-init-segment-received [Editor's Draft 09 January 2015]
958
959     // 1. Update the duration attribute if it currently equals NaN:
960     if (m_source->duration().isInvalid()) {
961         // ↳ If the initialization segment contains a duration:
962         //   Run the duration change algorithm with new duration set to the duration in the initialization segment.
963         // ↳ Otherwise:
964         //   Run the duration change algorithm with new duration set to positive Infinity.
965         MediaTime newDuration = segment.duration.isValid() ? segment.duration : MediaTime::positiveInfiniteTime();
966         m_source->setDurationInternal(newDuration);
967     }
968
969     // 2. If the initialization segment has no audio, video, or text tracks, then run the append error algorithm
970     // with the decode error parameter set to true and abort these steps.
971     if (segment.audioTracks.isEmpty() && segment.videoTracks.isEmpty() && segment.textTracks.isEmpty()) {
972         appendError(true);
973         return;
974     }
975
976     // 3. If the first initialization segment flag is true, then run the following steps:
977     if (m_receivedFirstInitializationSegment) {
978
979         // 3.1. Verify the following properties. If any of the checks fail then run the append error algorithm
980         // with the decode error parameter set to true and abort these steps.
981         if (!validateInitializationSegment(segment)) {
982             appendError(true);
983             return;
984         }
985         // 3.2 Add the appropriate track descriptions from this initialization segment to each of the track buffers.
986         ASSERT(segment.audioTracks.size() == audioTracks()->length());
987         for (auto& audioTrackInfo : segment.audioTracks) {
988             if (audioTracks()->length() == 1) {
989                 audioTracks()->item(0)->setPrivate(audioTrackInfo.track);
990                 break;
991             }
992
993             auto audioTrack = audioTracks()->getTrackById(audioTrackInfo.track->id());
994             ASSERT(audioTrack);
995             audioTrack->setPrivate(audioTrackInfo.track);
996         }
997
998         ASSERT(segment.videoTracks.size() == videoTracks()->length());
999         for (auto& videoTrackInfo : segment.videoTracks) {
1000             if (videoTracks()->length() == 1) {
1001                 videoTracks()->item(0)->setPrivate(videoTrackInfo.track);
1002                 break;
1003             }
1004
1005             auto videoTrack = videoTracks()->getTrackById(videoTrackInfo.track->id());
1006             ASSERT(videoTrack);
1007             videoTrack->setPrivate(videoTrackInfo.track);
1008         }
1009
1010         ASSERT(segment.textTracks.size() == textTracks()->length());
1011         for (auto& textTrackInfo : segment.textTracks) {
1012             if (textTracks()->length() == 1) {
1013                 downcast<InbandTextTrack>(*textTracks()->item(0)).setPrivate(textTrackInfo.track);
1014                 break;
1015             }
1016
1017             auto textTrack = textTracks()->getTrackById(textTrackInfo.track->id());
1018             ASSERT(textTrack);
1019             downcast<InbandTextTrack>(*textTrack).setPrivate(textTrackInfo.track);
1020         }
1021
1022         // 3.3 Set the need random access point flag on all track buffers to true.
1023         for (auto& trackBuffer : m_trackBufferMap.values())
1024             trackBuffer.needRandomAccessFlag = true;
1025     }
1026
1027     // 4. Let active track flag equal false.
1028     bool activeTrackFlag = false;
1029
1030     // 5. If the first initialization segment flag is false, then run the following steps:
1031     if (!m_receivedFirstInitializationSegment) {
1032         // 5.1 If the initialization segment contains tracks with codecs the user agent does not support,
1033         // then run the append error algorithm with the decode error parameter set to true and abort these steps.
1034         // NOTE: This check is the responsibility of the SourceBufferPrivate.
1035
1036         // 5.2 For each audio track in the initialization segment, run following steps:
1037         for (auto& audioTrackInfo : segment.audioTracks) {
1038             AudioTrackPrivate* audioTrackPrivate = audioTrackInfo.track.get();
1039
1040             // FIXME: Implement steps 5.2.1-5.2.8.1 as per Editor's Draft 09 January 2015, and reorder this
1041             // 5.2.1 Let new audio track be a new AudioTrack object.
1042             // 5.2.2 Generate a unique ID and assign it to the id property on new video track.
1043             RefPtr<AudioTrack> newAudioTrack = AudioTrack::create(this, audioTrackPrivate);
1044             newAudioTrack->setSourceBuffer(this);
1045
1046             // 5.2.3 If audioTracks.length equals 0, then run the following steps:
1047             if (!audioTracks()->length()) {
1048                 // 5.2.3.1 Set the enabled property on new audio track to true.
1049                 newAudioTrack->setEnabled(true);
1050
1051                 // 5.2.3.2 Set active track flag to true.
1052                 activeTrackFlag = true;
1053             }
1054
1055             // 5.2.4 Add new audio track to the audioTracks attribute on this SourceBuffer object.
1056             // 5.2.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1057             // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
1058             // referenced by the audioTracks attribute on this SourceBuffer object.
1059             audioTracks()->append(newAudioTrack);
1060
1061             // 5.2.6 Add new audio track to the audioTracks attribute on the HTMLMediaElement.
1062             // 5.2.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1063             // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
1064             // referenced by the audioTracks attribute on the HTMLMediaElement.
1065             m_source->mediaElement()->audioTracks()->append(newAudioTrack);
1066
1067             // 5.2.8 Create a new track buffer to store coded frames for this track.
1068             ASSERT(!m_trackBufferMap.contains(newAudioTrack->id()));
1069             TrackBuffer& trackBuffer = m_trackBufferMap.add(newAudioTrack->id(), TrackBuffer()).iterator->value;
1070
1071             // 5.2.9 Add the track description for this track to the track buffer.
1072             trackBuffer.description = audioTrackInfo.description;
1073
1074             m_audioCodecs.append(trackBuffer.description->codec());
1075         }
1076
1077         // 5.3 For each video track in the initialization segment, run following steps:
1078         for (auto& videoTrackInfo : segment.videoTracks) {
1079             VideoTrackPrivate* videoTrackPrivate = videoTrackInfo.track.get();
1080
1081             // FIXME: Implement steps 5.3.1-5.3.8.1 as per Editor's Draft 09 January 2015, and reorder this
1082             // 5.3.1 Let new video track be a new VideoTrack object.
1083             // 5.3.2 Generate a unique ID and assign it to the id property on new video track.
1084             RefPtr<VideoTrack> newVideoTrack = VideoTrack::create(this, videoTrackPrivate);
1085             newVideoTrack->setSourceBuffer(this);
1086
1087             // 5.3.3 If videoTracks.length equals 0, then run the following steps:
1088             if (!videoTracks()->length()) {
1089                 // 5.3.3.1 Set the selected property on new video track to true.
1090                 newVideoTrack->setSelected(true);
1091
1092                 // 5.3.3.2 Set active track flag to true.
1093                 activeTrackFlag = true;
1094             }
1095
1096             // 5.3.4 Add new video track to the videoTracks attribute on this SourceBuffer object.
1097             // 5.3.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1098             // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
1099             // referenced by the videoTracks attribute on this SourceBuffer object.
1100             videoTracks()->append(newVideoTrack);
1101
1102             // 5.3.6 Add new video track to the videoTracks attribute on the HTMLMediaElement.
1103             // 5.3.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1104             // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
1105             // referenced by the videoTracks attribute on the HTMLMediaElement.
1106             m_source->mediaElement()->videoTracks()->append(newVideoTrack);
1107
1108             // 5.3.8 Create a new track buffer to store coded frames for this track.
1109             ASSERT(!m_trackBufferMap.contains(newVideoTrack->id()));
1110             TrackBuffer& trackBuffer = m_trackBufferMap.add(newVideoTrack->id(), TrackBuffer()).iterator->value;
1111
1112             // 5.3.9 Add the track description for this track to the track buffer.
1113             trackBuffer.description = videoTrackInfo.description;
1114
1115             m_videoCodecs.append(trackBuffer.description->codec());
1116         }
1117
1118         // 5.4 For each text track in the initialization segment, run following steps:
1119         for (auto& textTrackInfo : segment.textTracks) {
1120             InbandTextTrackPrivate* textTrackPrivate = textTrackInfo.track.get();
1121
1122             // FIXME: Implement steps 5.4.1-5.4.8.1 as per Editor's Draft 09 January 2015, and reorder this
1123             // 5.4.1 Let new text track be a new TextTrack object with its properties populated with the
1124             // appropriate information from the initialization segment.
1125             RefPtr<InbandTextTrack> newTextTrack = InbandTextTrack::create(scriptExecutionContext(), this, textTrackPrivate);
1126
1127             // 5.4.2 If the mode property on new text track equals "showing" or "hidden", then set active
1128             // track flag to true.
1129             if (textTrackPrivate->mode() != InbandTextTrackPrivate::Disabled)
1130                 activeTrackFlag = true;
1131
1132             // 5.4.3 Add new text track to the textTracks attribute on this SourceBuffer object.
1133             // 5.4.4 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1134             // not cancelable, and that uses the TrackEvent interface, at textTracks attribute on this
1135             // SourceBuffer object.
1136             textTracks()->append(newTextTrack);
1137
1138             // 5.4.5 Add new text track to the textTracks attribute on the HTMLMediaElement.
1139             // 5.4.6 Queue a task to fire a trusted event named addtrack, that does not bubble and is
1140             // not cancelable, and that uses the TrackEvent interface, at the TextTrackList object
1141             // referenced by the textTracks attribute on the HTMLMediaElement.
1142             m_source->mediaElement()->textTracks()->append(newTextTrack);
1143
1144             // 5.4.7 Create a new track buffer to store coded frames for this track.
1145             ASSERT(!m_trackBufferMap.contains(textTrackPrivate->id()));
1146             TrackBuffer& trackBuffer = m_trackBufferMap.add(textTrackPrivate->id(), TrackBuffer()).iterator->value;
1147
1148             // 5.4.8 Add the track description for this track to the track buffer.
1149             trackBuffer.description = textTrackInfo.description;
1150
1151             m_textCodecs.append(trackBuffer.description->codec());
1152         }
1153
1154         // 5.5 If active track flag equals true, then run the following steps:
1155         if (activeTrackFlag) {
1156             // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
1157             // 5.5.2 Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1158             setActive(true);
1159         }
1160
1161         // 5.6 Set first initialization segment flag to true.
1162         m_receivedFirstInitializationSegment = true;
1163     }
1164
1165     // 6. If the HTMLMediaElement.readyState attribute is HAVE_NOTHING, then run the following steps:
1166     if (m_private->readyState() == MediaPlayer::HaveNothing) {
1167         // 6.1 If one or more objects in sourceBuffers have first initialization segment flag set to false, then abort these steps.
1168         for (auto& sourceBuffer : *m_source->sourceBuffers()) {
1169             if (!sourceBuffer->m_receivedFirstInitializationSegment)
1170                 return;
1171         }
1172
1173         // 6.2 Set the HTMLMediaElement.readyState attribute to HAVE_METADATA.
1174         // 6.3 Queue a task to fire a simple event named loadedmetadata at the media element.
1175         m_private->setReadyState(MediaPlayer::HaveMetadata);
1176     }
1177
1178     // 7. If the active track flag equals true and the HTMLMediaElement.readyState
1179     // attribute is greater than HAVE_CURRENT_DATA, then set the HTMLMediaElement.readyState
1180     // attribute to HAVE_METADATA.
1181     if (activeTrackFlag && m_private->readyState() > MediaPlayer::HaveCurrentData)
1182         m_private->setReadyState(MediaPlayer::HaveMetadata);
1183 }
1184
1185 bool SourceBuffer::validateInitializationSegment(const InitializationSegment& segment)
1186 {
1187     // FIXME: ordering of all 3.5.X (X>=7) functions needs to be updated to post-[24 July 2014 Editor's Draft] version
1188     // 3.5.8 Initialization Segment Received (ctd)
1189     // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-init-segment-received [Editor's Draft 09 January 2015]
1190
1191     // Note: those are checks from step 3.1
1192     //   * The number of audio, video, and text tracks match what was in the first initialization segment.
1193     if (segment.audioTracks.size() != audioTracks()->length()
1194         || segment.videoTracks.size() != videoTracks()->length()
1195         || segment.textTracks.size() != textTracks()->length())
1196         return false;
1197
1198     //   * The codecs for each track, match what was specified in the first initialization segment.
1199     for (auto& audioTrackInfo : segment.audioTracks) {
1200         if (!m_audioCodecs.contains(audioTrackInfo.description->codec()))
1201             return false;
1202     }
1203
1204     for (auto& videoTrackInfo : segment.videoTracks) {
1205         if (!m_videoCodecs.contains(videoTrackInfo.description->codec()))
1206             return false;
1207     }
1208
1209     for (auto& textTrackInfo : segment.textTracks) {
1210         if (!m_textCodecs.contains(textTrackInfo.description->codec()))
1211             return false;
1212     }
1213
1214     //   * If more than one track for a single type are present (ie 2 audio tracks), then the Track
1215     //   IDs match the ones in the first initialization segment.
1216     if (segment.audioTracks.size() >= 2) {
1217         for (auto& audioTrackInfo : segment.audioTracks) {
1218             if (!m_trackBufferMap.contains(audioTrackInfo.track->id()))
1219                 return false;
1220         }
1221     }
1222
1223     if (segment.videoTracks.size() >= 2) {
1224         for (auto& videoTrackInfo : segment.videoTracks) {
1225             if (!m_trackBufferMap.contains(videoTrackInfo.track->id()))
1226                 return false;
1227         }
1228     }
1229
1230     if (segment.textTracks.size() >= 2) {
1231         for (auto& textTrackInfo : segment.videoTracks) {
1232             if (!m_trackBufferMap.contains(textTrackInfo.track->id()))
1233                 return false;
1234         }
1235     }
1236
1237     return true;
1238 }
1239
1240 class SampleLessThanComparator {
1241 public:
1242     bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
1243     {
1244         return value1.first < value2.first;
1245     }
1246
1247     bool operator()(MediaTime value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
1248     {
1249         return value1 < value2.first;
1250     }
1251
1252     bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, MediaTime value2)
1253     {
1254         return value1.first < value2;
1255     }
1256 };
1257
1258 void SourceBuffer::appendError(bool decodeErrorParam)
1259 {
1260     // 3.5.3 Append Error Algorithm
1261     // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-append-error [Editor's Draft 09 January 2015]
1262
1263     ASSERT(m_updating);
1264     // 1. Run the reset parser state algorithm.
1265     resetParserState();
1266
1267     // 2. Set the updating attribute to false.
1268     m_updating = false;
1269
1270     // 3. Queue a task to fire a simple event named error at this SourceBuffer object.
1271     scheduleEvent(eventNames().errorEvent);
1272
1273     // 4. Queue a task to fire a simple event named updateend at this SourceBuffer object.
1274     scheduleEvent(eventNames().updateendEvent);
1275
1276     // 5. If decode error is true, then run the end of stream algorithm with the error parameter set to "decode".
1277     if (decodeErrorParam)
1278         m_source->streamEndedWithError(EndOfStreamError::Decode);
1279 }
1280
1281 void SourceBuffer::sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample> prpSample)
1282 {
1283     if (isRemoved())
1284         return;
1285
1286     // 3.5.1 Segment Parser Loop
1287     // 6.1 If the first initialization segment received flag is false, then run the append error algorithm
1288     //     with the decode error parameter set to true and abort this algorithm.
1289     // Note: current design makes SourceBuffer somehow ignorant of append state - it's more a thing
1290     //  of SourceBufferPrivate. That's why this check can't really be done in appendInternal.
1291     //  unless we force some kind of design with state machine switching.
1292     if (!m_receivedFirstInitializationSegment) {
1293         appendError(true);
1294         return;
1295     }
1296
1297     RefPtr<MediaSample> sample = prpSample;
1298
1299     // 3.5.8 Coded Frame Processing
1300     // http://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-processing
1301
1302     // When complete coded frames have been parsed by the segment parser loop then the following steps
1303     // are run:
1304     // 1. For each coded frame in the media segment run the following steps:
1305     // 1.1. Loop Top
1306     do {
1307         MediaTime presentationTimestamp;
1308         MediaTime decodeTimestamp;
1309
1310         if (m_shouldGenerateTimestamps) {
1311             // ↳ If generate timestamps flag equals true:
1312             // 1. Let presentation timestamp equal 0.
1313             presentationTimestamp = MediaTime::zeroTime();
1314
1315             // 2. Let decode timestamp equal 0.
1316             decodeTimestamp = MediaTime::zeroTime();
1317         } else {
1318             // ↳ Otherwise:
1319             // 1. Let presentation timestamp be a double precision floating point representation of
1320             // the coded frame's presentation timestamp in seconds.
1321             presentationTimestamp = sample->presentationTime();
1322
1323             // 2. Let decode timestamp be a double precision floating point representation of the coded frame's
1324             // decode timestamp in seconds.
1325             decodeTimestamp = sample->decodeTime();
1326         }
1327
1328         // 1.2 Let frame duration be a double precision floating point representation of the coded frame's
1329         // duration in seconds.
1330         MediaTime frameDuration = sample->duration();
1331
1332         // 1.3 If mode equals "sequence" and group start timestamp is set, then run the following steps:
1333         if (m_mode == AppendMode::Sequence && m_groupStartTimestamp.isValid()) {
1334             // 1.3.1 Set timestampOffset equal to group start timestamp - presentation timestamp.
1335             m_timestampOffset = m_groupStartTimestamp;
1336
1337             // 1.3.2 Set group end timestamp equal to group start timestamp.
1338             m_groupEndTimestamp = m_groupStartTimestamp;
1339
1340             // 1.3.3 Set the need random access point flag on all track buffers to true.
1341             for (auto& trackBuffer : m_trackBufferMap.values())
1342                 trackBuffer.needRandomAccessFlag = true;
1343
1344             // 1.3.4 Unset group start timestamp.
1345             m_groupStartTimestamp = MediaTime::invalidTime();
1346         }
1347
1348         // 1.4 If timestampOffset is not 0, then run the following steps:
1349         if (m_timestampOffset) {
1350             // 1.4.1 Add timestampOffset to the presentation timestamp.
1351             presentationTimestamp += m_timestampOffset;
1352
1353             // 1.4.2 Add timestampOffset to the decode timestamp.
1354             decodeTimestamp += m_timestampOffset;
1355         }
1356
1357         // 1.5 Let track buffer equal the track buffer that the coded frame will be added to.
1358         AtomicString trackID = sample->trackID();
1359         auto it = m_trackBufferMap.find(trackID);
1360         if (it == m_trackBufferMap.end())
1361             it = m_trackBufferMap.add(trackID, TrackBuffer()).iterator;
1362         TrackBuffer& trackBuffer = it->value;
1363
1364         // 1.6 ↳ If last decode timestamp for track buffer is set and decode timestamp is less than last
1365         // decode timestamp:
1366         // OR
1367         // ↳ If last decode timestamp for track buffer is set and the difference between decode timestamp and
1368         // last decode timestamp is greater than 2 times last frame duration:
1369         if (trackBuffer.lastDecodeTimestamp.isValid() && (decodeTimestamp < trackBuffer.lastDecodeTimestamp
1370             || abs(decodeTimestamp - trackBuffer.lastDecodeTimestamp) > (trackBuffer.lastFrameDuration * 2))) {
1371
1372             // 1.6.1:
1373             if (m_mode == AppendMode::Segments) {
1374                 // ↳ If mode equals "segments":
1375                 // Set group end timestamp to presentation timestamp.
1376                 m_groupEndTimestamp = presentationTimestamp;
1377             } else {
1378                 // ↳ If mode equals "sequence":
1379                 // Set group start timestamp equal to the group end timestamp.
1380                 m_groupStartTimestamp = m_groupEndTimestamp;
1381             }
1382
1383             for (auto& trackBuffer : m_trackBufferMap.values()) {
1384                 // 1.6.2 Unset the last decode timestamp on all track buffers.
1385                 trackBuffer.lastDecodeTimestamp = MediaTime::invalidTime();
1386                 // 1.6.3 Unset the last frame duration on all track buffers.
1387                 trackBuffer.lastFrameDuration = MediaTime::invalidTime();
1388                 // 1.6.4 Unset the highest presentation timestamp on all track buffers.
1389                 trackBuffer.highestPresentationTimestamp = MediaTime::invalidTime();
1390                 // 1.6.5 Set the need random access point flag on all track buffers to true.
1391                 trackBuffer.needRandomAccessFlag = true;
1392             }
1393
1394             // 1.6.6 Jump to the Loop Top step above to restart processing of the current coded frame.
1395             continue;
1396         }
1397
1398         if (m_mode == AppendMode::Sequence) {
1399             // Use the generated timestamps instead of the sample's timestamps.
1400             sample->setTimestamps(presentationTimestamp, decodeTimestamp);
1401         } else if (m_timestampOffset) {
1402             // Reflect the timestamp offset into the sample.
1403             sample->offsetTimestampsBy(m_timestampOffset);
1404         }
1405
1406         // 1.7 Let frame end timestamp equal the sum of presentation timestamp and frame duration.
1407         MediaTime frameEndTimestamp = presentationTimestamp + frameDuration;
1408
1409         // 1.8 If presentation timestamp is less than appendWindowStart, then set the need random access
1410         // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
1411         // the next coded frame.
1412         // 1.9 If frame end timestamp is greater than appendWindowEnd, then set the need random access
1413         // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
1414         // the next coded frame.
1415         if (presentationTimestamp < m_appendWindowStart || frameEndTimestamp > m_appendWindowEnd) {
1416             trackBuffer.needRandomAccessFlag = true;
1417             didDropSample();
1418             return;
1419         }
1420
1421
1422         // 1.10 If the decode timestamp is less than the presentation start time, then run the end of stream
1423         // algorithm with the error parameter set to "decode", and abort these steps.
1424         // NOTE: Until <https://www.w3.org/Bugs/Public/show_bug.cgi?id=27487> is resolved, we will only check
1425         // the presentation timestamp.
1426         MediaTime presentationStartTime = MediaTime::zeroTime();
1427         if (presentationTimestamp < presentationStartTime) {
1428             LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidReceiveSample(%p) - failing because presentationTimestamp < presentationStartTime", this);
1429             m_source->streamEndedWithError(EndOfStreamError::Decode);
1430             return;
1431         }
1432
1433         // 1.11 If the need random access point flag on track buffer equals true, then run the following steps:
1434         if (trackBuffer.needRandomAccessFlag) {
1435             // 1.11.1 If the coded frame is not a random access point, then drop the coded frame and jump
1436             // to the top of the loop to start processing the next coded frame.
1437             if (!sample->isSync()) {
1438                 didDropSample();
1439                 return;
1440             }
1441
1442             // 1.11.2 Set the need random access point flag on track buffer to false.
1443             trackBuffer.needRandomAccessFlag = false;
1444         }
1445
1446         // 1.12 Let spliced audio frame be an unset variable for holding audio splice information
1447         // 1.13 Let spliced timed text frame be an unset variable for holding timed text splice information
1448         // FIXME: Add support for sample splicing.
1449
1450         SampleMap erasedSamples;
1451         MediaTime microsecond(1, 1000000);
1452
1453         // 1.14 If last decode timestamp for track buffer is unset and presentation timestamp falls
1454         // falls within the presentation interval of a coded frame in track buffer, then run the
1455         // following steps:
1456         if (trackBuffer.lastDecodeTimestamp.isInvalid()) {
1457             auto iter = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(presentationTimestamp);
1458             if (iter != trackBuffer.samples.presentationOrder().end()) {
1459                 // 1.14.1 Let overlapped frame be the coded frame in track buffer that matches the condition above.
1460                 RefPtr<MediaSample> overlappedFrame = iter->second;
1461
1462                 // 1.14.2 If track buffer contains audio coded frames:
1463                 // Run the audio splice frame algorithm and if a splice frame is returned, assign it to
1464                 // spliced audio frame.
1465                 // FIXME: Add support for sample splicing.
1466
1467                 // If track buffer contains video coded frames:
1468                 if (trackBuffer.description->isVideo()) {
1469                     // 1.14.2.1 Let overlapped frame presentation timestamp equal the presentation timestamp
1470                     // of overlapped frame.
1471                     MediaTime overlappedFramePresentationTimestamp = overlappedFrame->presentationTime();
1472
1473                     // 1.14.2.2 Let remove window timestamp equal overlapped frame presentation timestamp
1474                     // plus 1 microsecond.
1475                     MediaTime removeWindowTimestamp = overlappedFramePresentationTimestamp + microsecond;
1476
1477                     // 1.14.2.3 If the presentation timestamp is less than the remove window timestamp,
1478                     // then remove overlapped frame and any coded frames that depend on it from track buffer.
1479                     if (presentationTimestamp < removeWindowTimestamp)
1480                         erasedSamples.addSample(iter->second);
1481                 }
1482
1483                 // If track buffer contains timed text coded frames:
1484                 // Run the text splice frame algorithm and if a splice frame is returned, assign it to spliced timed text frame.
1485                 // FIXME: Add support for sample splicing.
1486             }
1487         }
1488
1489         // 1.15 Remove existing coded frames in track buffer:
1490         // If highest presentation timestamp for track buffer is not set:
1491         if (trackBuffer.highestPresentationTimestamp.isInvalid()) {
1492             // Remove all coded frames from track buffer that have a presentation timestamp greater than or
1493             // equal to presentation timestamp and less than frame end timestamp.
1494             auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesBetweenPresentationTimes(presentationTimestamp, frameEndTimestamp);
1495             if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
1496                 erasedSamples.addRange(iter_pair.first, iter_pair.second);
1497         }
1498
1499         // If highest presentation timestamp for track buffer is set and less than or equal to presentation timestamp
1500         if (trackBuffer.highestPresentationTimestamp.isValid() && trackBuffer.highestPresentationTimestamp <= presentationTimestamp) {
1501             // Remove all coded frames from track buffer that have a presentation timestamp greater than highest
1502             // presentation timestamp and less than or equal to frame end timestamp.
1503             do {
1504                 // NOTE: Searching from the end of the trackBuffer will be vastly more efficient if the search range is
1505                 // near the end of the buffered range. Use a linear-backwards search if the search range is within one
1506                 // frame duration of the end:
1507                 if (!m_buffered)
1508                     break;
1509
1510                 unsigned bufferedLength = m_buffered->ranges().length();
1511                 if (!bufferedLength)
1512                     break;
1513
1514                 MediaTime highestBufferedTime = m_buffered->ranges().maximumBufferedTime();
1515
1516                 PresentationOrderSampleMap::iterator_range range;
1517                 if (highestBufferedTime - trackBuffer.highestPresentationTimestamp < trackBuffer.lastFrameDuration)
1518                     range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRangeFromEnd(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
1519                 else
1520                     range = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
1521
1522                 if (range.first != trackBuffer.samples.presentationOrder().end())
1523                     erasedSamples.addRange(range.first, range.second);
1524             } while(false);
1525         }
1526
1527         // 1.16 Remove decoding dependencies of the coded frames removed in the previous step:
1528         DecodeOrderSampleMap::MapType dependentSamples;
1529         if (!erasedSamples.empty()) {
1530             // If detailed information about decoding dependencies is available:
1531             // FIXME: Add support for detailed dependency information
1532
1533             // Otherwise: Remove all coded frames between the coded frames removed in the previous step
1534             // and the next random access point after those removed frames.
1535             auto firstDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeKey(erasedSamples.decodeOrder().begin()->first);
1536             auto lastDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeKey(erasedSamples.decodeOrder().rbegin()->first);
1537             auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(lastDecodeIter);
1538             dependentSamples.insert(firstDecodeIter, nextSyncIter);
1539
1540             RefPtr<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer, this, "sourceBufferPrivateDidReceiveSample");
1541
1542             // Only force the TrackBuffer to re-enqueue if the removed ranges overlap with enqueued and possibly
1543             // not yet displayed samples.
1544             MediaTime currentMediaTime = m_source->currentTime();
1545             if (currentMediaTime < trackBuffer.lastEnqueuedPresentationTime) {
1546                 PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
1547                 possiblyEnqueuedRanges.intersectWith(erasedRanges->ranges());
1548                 if (possiblyEnqueuedRanges.length())
1549                     trackBuffer.needsReenqueueing = true;
1550             }
1551
1552             erasedRanges->invert();
1553             m_buffered->intersectWith(*erasedRanges);
1554             setBufferedDirty(true);
1555         }
1556
1557         // 1.17 If spliced audio frame is set:
1558         // Add spliced audio frame to the track buffer.
1559         // If spliced timed text frame is set:
1560         // Add spliced timed text frame to the track buffer.
1561         // FIXME: Add support for sample splicing.
1562
1563         // Otherwise:
1564         // Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
1565         trackBuffer.samples.addSample(sample);
1566
1567         if (trackBuffer.lastEnqueuedDecodeEndTime.isInvalid() || decodeTimestamp >= trackBuffer.lastEnqueuedDecodeEndTime) {
1568             DecodeOrderSampleMap::KeyType decodeKey(decodeTimestamp, presentationTimestamp);
1569             trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, sample));
1570         }
1571
1572         // 1.18 Set last decode timestamp for track buffer to decode timestamp.
1573         trackBuffer.lastDecodeTimestamp = decodeTimestamp;
1574
1575         // 1.19 Set last frame duration for track buffer to frame duration.
1576         trackBuffer.lastFrameDuration = frameDuration;
1577
1578         // 1.20 If highest presentation timestamp for track buffer is unset or frame end timestamp is greater
1579         // than highest presentation timestamp, then set highest presentation timestamp for track buffer
1580         // to frame end timestamp.
1581         if (trackBuffer.highestPresentationTimestamp.isInvalid() || frameEndTimestamp > trackBuffer.highestPresentationTimestamp)
1582             trackBuffer.highestPresentationTimestamp = frameEndTimestamp;
1583
1584         // 1.21 If frame end timestamp is greater than group end timestamp, then set group end timestamp equal
1585         // to frame end timestamp.
1586         if (m_groupEndTimestamp.isInvalid() || frameEndTimestamp > m_groupEndTimestamp)
1587             m_groupEndTimestamp = frameEndTimestamp;
1588
1589         // 1.22 If generate timestamps flag equals true, then set timestampOffset equal to frame end timestamp.
1590         if (m_shouldGenerateTimestamps)
1591             m_timestampOffset = frameEndTimestamp;
1592
1593         m_buffered->add(presentationTimestamp.toDouble(), (presentationTimestamp + frameDuration + microsecond).toDouble());
1594         m_bufferedSinceLastMonitor += frameDuration.toDouble();
1595         setBufferedDirty(true);
1596
1597         break;
1598     } while (1);
1599
1600     // Steps 2-4 will be handled by MediaSource::monitorSourceBuffers()
1601
1602     // 5. If the media segment contains data beyond the current duration, then run the duration change algorithm with new
1603     // duration set to the maximum of the current duration and the group end timestamp.
1604     if (m_groupEndTimestamp > m_source->duration())
1605         m_source->setDurationInternal(m_groupEndTimestamp);
1606 }
1607
1608 bool SourceBuffer::hasAudio() const
1609 {
1610     return m_audioTracks && m_audioTracks->length();
1611 }
1612
1613 bool SourceBuffer::hasVideo() const
1614 {
1615     return m_videoTracks && m_videoTracks->length();
1616 }
1617
1618 bool SourceBuffer::sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const
1619 {
1620     return hasAudio();
1621 }
1622
1623 bool SourceBuffer::sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const
1624 {
1625     return hasVideo();
1626 }
1627
1628 void SourceBuffer::videoTrackSelectedChanged(VideoTrack* track)
1629 {
1630     // 2.4.5 Changes to selected/enabled track state
1631     // If the selected video track changes, then run the following steps:
1632     // 1. If the SourceBuffer associated with the previously selected video track is not associated with
1633     // any other enabled tracks, run the following steps:
1634     if (track->selected()
1635         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1636         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1637         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1638         // 1.1 Remove the SourceBuffer from activeSourceBuffers.
1639         // 1.2 Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1640         setActive(false);
1641     } else if (!track->selected()) {
1642         // 2. If the SourceBuffer associated with the newly selected video track is not already in activeSourceBuffers,
1643         // run the following steps:
1644         // 2.1 Add the SourceBuffer to activeSourceBuffers.
1645         // 2.2 Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1646         setActive(true);
1647     }
1648
1649     if (!isRemoved())
1650         m_source->mediaElement()->videoTrackSelectedChanged(track);
1651 }
1652
1653 void SourceBuffer::audioTrackEnabledChanged(AudioTrack* track)
1654 {
1655     // 2.4.5 Changes to selected/enabled track state
1656     // If an audio track becomes disabled and the SourceBuffer associated with this track is not
1657     // associated with any other enabled or selected track, then run the following steps:
1658     if (track->enabled()
1659         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1660         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1661         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1662         // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
1663         // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1664         setActive(false);
1665     } else if (!track->enabled()) {
1666         // If an audio track becomes enabled and the SourceBuffer associated with this track is
1667         // not already in activeSourceBuffers, then run the following steps:
1668         // 1. Add the SourceBuffer associated with the audio track to activeSourceBuffers
1669         // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1670         setActive(true);
1671     }
1672
1673     if (!isRemoved())
1674         m_source->mediaElement()->audioTrackEnabledChanged(track);
1675 }
1676
1677 void SourceBuffer::textTrackModeChanged(TextTrack* track)
1678 {
1679     // 2.4.5 Changes to selected/enabled track state
1680     // If a text track mode becomes "disabled" and the SourceBuffer associated with this track is not
1681     // associated with any other enabled or selected track, then run the following steps:
1682     if (track->mode() == TextTrack::disabledKeyword()
1683         && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
1684         && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
1685         && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
1686         // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
1687         // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
1688         setActive(false);
1689     } else {
1690         // If a text track mode becomes "showing" or "hidden" and the SourceBuffer associated with this
1691         // track is not already in activeSourceBuffers, then run the following steps:
1692         // 1. Add the SourceBuffer associated with the text track to activeSourceBuffers
1693         // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
1694         setActive(true);
1695     }
1696
1697     if (!isRemoved())
1698         m_source->mediaElement()->textTrackModeChanged(track);
1699 }
1700
1701 void SourceBuffer::textTrackAddCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
1702 {
1703     if (!isRemoved())
1704         m_source->mediaElement()->textTrackAddCue(track, cue);
1705 }
1706
1707 void SourceBuffer::textTrackAddCues(TextTrack* track, TextTrackCueList const* cueList)
1708 {
1709     if (!isRemoved())
1710         m_source->mediaElement()->textTrackAddCues(track, cueList);
1711 }
1712
1713 void SourceBuffer::textTrackRemoveCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
1714 {
1715     if (!isRemoved())
1716         m_source->mediaElement()->textTrackRemoveCue(track, cue);
1717 }
1718
1719 void SourceBuffer::textTrackRemoveCues(TextTrack* track, TextTrackCueList const* cueList)
1720 {
1721     if (!isRemoved())
1722         m_source->mediaElement()->textTrackRemoveCues(track, cueList);
1723 }
1724
1725 void SourceBuffer::textTrackKindChanged(TextTrack* track)
1726 {
1727     if (!isRemoved())
1728         m_source->mediaElement()->textTrackKindChanged(track);
1729 }
1730
1731 void SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples(SourceBufferPrivate*, AtomicString trackID)
1732 {
1733     LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples(%p)", this);
1734     auto it = m_trackBufferMap.find(trackID);
1735     if (it == m_trackBufferMap.end())
1736         return;
1737
1738     TrackBuffer& trackBuffer = it->value;
1739     if (!trackBuffer.needsReenqueueing && !m_source->isSeeking())
1740         provideMediaData(trackBuffer, trackID);
1741 }
1742
1743 void SourceBuffer::provideMediaData(TrackBuffer& trackBuffer, AtomicString trackID)
1744 {
1745 #if !LOG_DISABLED
1746     unsigned enqueuedSamples = 0;
1747 #endif
1748
1749     while (!trackBuffer.decodeQueue.empty()) {
1750         if (!m_private->isReadyForMoreSamples(trackID)) {
1751             m_private->notifyClientWhenReadyForMoreSamples(trackID);
1752             break;
1753         }
1754
1755         // FIXME(rdar://problem/20635969): Remove this re-entrancy protection when the aforementioned radar is resolved; protecting
1756         // against re-entrancy introduces a small inefficency when removing appended samples from the decode queue one at a time
1757         // rather than when all samples have been enqueued.
1758         RefPtr<MediaSample> sample = trackBuffer.decodeQueue.begin()->second;
1759         trackBuffer.decodeQueue.erase(trackBuffer.decodeQueue.begin());
1760
1761         // Do not enqueue samples spanning a significant unbuffered gap.
1762         // NOTE: one second is somewhat arbitrary. MediaSource::monitorSourceBuffers() is run
1763         // on the playbackTimer, which is effectively every 350ms. Allowing > 350ms gap between
1764         // enqueued samples allows for situations where we overrun the end of a buffered range
1765         // but don't notice for 350s of playback time, and the client can enqueue data for the
1766         // new current time without triggering this early return.
1767         // FIXME(135867): Make this gap detection logic less arbitrary.
1768         MediaTime oneSecond(1, 1);
1769         if (trackBuffer.lastEnqueuedDecodeEndTime.isValid() && sample->decodeTime() - trackBuffer.lastEnqueuedDecodeEndTime > oneSecond)
1770             break;
1771
1772         trackBuffer.lastEnqueuedPresentationTime = sample->presentationTime();
1773         trackBuffer.lastEnqueuedDecodeEndTime = sample->decodeTime() + sample->duration();
1774         m_private->enqueueSample(sample.release(), trackID);
1775 #if !LOG_DISABLED
1776         ++enqueuedSamples;
1777 #endif
1778     }
1779
1780     LOG(MediaSource, "SourceBuffer::provideMediaData(%p) - Enqueued %u samples", this, enqueuedSamples);
1781 }
1782
1783 void SourceBuffer::reenqueueMediaForTime(TrackBuffer& trackBuffer, AtomicString trackID, const MediaTime& time)
1784 {
1785     // Find the sample which contains the current presentation time.
1786     auto currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(time);
1787
1788     if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end()) {
1789         trackBuffer.decodeQueue.clear();
1790         m_private->flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample>>(), trackID);
1791         return;
1792     }
1793
1794     // Seach backward for the previous sync sample.
1795     DecodeOrderSampleMap::KeyType decodeKey(currentSamplePTSIterator->second->decodeTime(), currentSamplePTSIterator->second->presentationTime());
1796     auto currentSampleDTSIterator = trackBuffer.samples.decodeOrder().findSampleWithDecodeKey(decodeKey);
1797     ASSERT(currentSampleDTSIterator != trackBuffer.samples.decodeOrder().end());
1798
1799     auto reverseCurrentSampleIter = --DecodeOrderSampleMap::reverse_iterator(currentSampleDTSIterator);
1800     auto reverseLastSyncSampleIter = trackBuffer.samples.decodeOrder().findSyncSamplePriorToDecodeIterator(reverseCurrentSampleIter);
1801     if (reverseLastSyncSampleIter == trackBuffer.samples.decodeOrder().rend()) {
1802         trackBuffer.decodeQueue.clear();
1803         m_private->flushAndEnqueueNonDisplayingSamples(Vector<RefPtr<MediaSample>>(), trackID);
1804         return;
1805     }
1806
1807     Vector<RefPtr<MediaSample>> nonDisplayingSamples;
1808     for (auto iter = reverseLastSyncSampleIter; iter != reverseCurrentSampleIter; --iter)
1809         nonDisplayingSamples.append(iter->second);
1810
1811     m_private->flushAndEnqueueNonDisplayingSamples(nonDisplayingSamples, trackID);
1812
1813     if (!nonDisplayingSamples.isEmpty()) {
1814         trackBuffer.lastEnqueuedPresentationTime = nonDisplayingSamples.last()->presentationTime();
1815         trackBuffer.lastEnqueuedDecodeEndTime = nonDisplayingSamples.last()->decodeTime();
1816     } else {
1817         trackBuffer.lastEnqueuedPresentationTime = MediaTime::invalidTime();
1818         trackBuffer.lastEnqueuedDecodeEndTime = MediaTime::invalidTime();
1819     }
1820
1821     // Fill the decode queue with the remaining samples.
1822     trackBuffer.decodeQueue.clear();
1823     for (auto iter = currentSampleDTSIterator; iter != trackBuffer.samples.decodeOrder().end(); ++iter)
1824         trackBuffer.decodeQueue.insert(*iter);
1825     provideMediaData(trackBuffer, trackID);
1826
1827     trackBuffer.needsReenqueueing = false;
1828 }
1829
1830
1831 void SourceBuffer::didDropSample()
1832 {
1833     if (!isRemoved())
1834         m_source->mediaElement()->incrementDroppedFrameCount();
1835 }
1836
1837 void SourceBuffer::monitorBufferingRate()
1838 {
1839     if (!m_bufferedSinceLastMonitor)
1840         return;
1841
1842     double now = monotonicallyIncreasingTime();
1843     double interval = now - m_timeOfBufferingMonitor;
1844     double rateSinceLastMonitor = m_bufferedSinceLastMonitor / interval;
1845
1846     m_timeOfBufferingMonitor = now;
1847     m_bufferedSinceLastMonitor = 0;
1848
1849     m_averageBufferRate = m_averageBufferRate * (1 - ExponentialMovingAverageCoefficient) + rateSinceLastMonitor * ExponentialMovingAverageCoefficient;
1850
1851     LOG(MediaSource, "SourceBuffer::monitorBufferingRate(%p) - m_avegareBufferRate: %lf", this, m_averageBufferRate);
1852 }
1853
1854 std::unique_ptr<PlatformTimeRanges> SourceBuffer::bufferedAccountingForEndOfStream() const
1855 {
1856     // FIXME: Revisit this method once the spec bug <https://www.w3.org/Bugs/Public/show_bug.cgi?id=26436> is resolved.
1857     auto virtualRanges = std::make_unique<PlatformTimeRanges>(m_buffered->ranges());
1858     if (m_source->isEnded()) {
1859         MediaTime start = virtualRanges->maximumBufferedTime();
1860         MediaTime end = m_source->duration();
1861         if (start <= end)
1862             virtualRanges->add(start, end);
1863     }
1864     return virtualRanges;
1865 }
1866
1867 bool SourceBuffer::hasCurrentTime() const
1868 {
1869     if (isRemoved() || !m_buffered->length())
1870         return false;
1871
1872     MediaTime currentTime = m_source->currentTime();
1873     MediaTime duration = m_source->duration();
1874     if (currentTime >= duration)
1875         return true;
1876
1877     std::unique_ptr<PlatformTimeRanges> ranges = bufferedAccountingForEndOfStream();
1878     return abs(ranges->nearest(currentTime) - currentTime) <= currentTimeFudgeFactor();
1879 }
1880
1881 bool SourceBuffer::hasFutureTime() const
1882 {
1883     if (isRemoved())
1884         return false;
1885
1886     std::unique_ptr<PlatformTimeRanges> ranges = bufferedAccountingForEndOfStream();
1887     if (!ranges->length())
1888         return false;
1889
1890     MediaTime currentTime = m_source->currentTime();
1891     MediaTime duration = m_source->duration();
1892     if (currentTime >= duration)
1893         return true;
1894
1895     MediaTime nearest = ranges->nearest(currentTime);
1896     if (abs(nearest - currentTime) > currentTimeFudgeFactor())
1897         return false;
1898
1899     size_t found = ranges->find(nearest);
1900     if (found == notFound)
1901         return false;
1902
1903     MediaTime localEnd = ranges->end(found);
1904     if (localEnd == duration)
1905         return true;
1906
1907     return localEnd - currentTime > currentTimeFudgeFactor();
1908 }
1909
1910 bool SourceBuffer::canPlayThrough()
1911 {
1912     if (isRemoved())
1913         return false;
1914
1915     monitorBufferingRate();
1916
1917     // Assuming no fluctuations in the buffering rate, loading 1 second per second or greater
1918     // means indefinite playback. This could be improved by taking jitter into account.
1919     if (m_averageBufferRate > 1)
1920         return true;
1921
1922     // Add up all the time yet to be buffered.
1923     MediaTime currentTime = m_source->currentTime();
1924     MediaTime duration = m_source->duration();
1925
1926     std::unique_ptr<PlatformTimeRanges> unbufferedRanges = bufferedAccountingForEndOfStream();
1927     unbufferedRanges->invert();
1928     unbufferedRanges->intersectWith(PlatformTimeRanges(currentTime, std::max(currentTime, duration)));
1929     MediaTime unbufferedTime = unbufferedRanges->totalDuration();
1930     if (!unbufferedTime.isValid())
1931         return true;
1932
1933     MediaTime timeRemaining = duration - currentTime;
1934     return unbufferedTime.toDouble() / m_averageBufferRate < timeRemaining.toDouble();
1935 }
1936
1937 size_t SourceBuffer::extraMemoryCost() const
1938 {
1939     size_t extraMemoryCost = m_pendingAppendData.capacity();
1940     for (auto& trackBuffer : m_trackBufferMap.values())
1941         extraMemoryCost += trackBuffer.samples.sizeInBytes();
1942
1943     return extraMemoryCost;
1944 }
1945
1946 void SourceBuffer::reportExtraMemoryAllocated()
1947 {
1948     size_t extraMemoryCost = this->extraMemoryCost();
1949     if (extraMemoryCost <= m_reportedExtraMemoryCost)
1950         return;
1951
1952     size_t extraMemoryCostDelta = extraMemoryCost - m_reportedExtraMemoryCost;
1953     m_reportedExtraMemoryCost = extraMemoryCost;
1954
1955     JSC::JSLockHolder lock(scriptExecutionContext()->vm());
1956     // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
1957     // https://bugs.webkit.org/show_bug.cgi?id=142595
1958     scriptExecutionContext()->vm().heap.deprecatedReportExtraMemory(extraMemoryCostDelta);
1959 }
1960
1961 Vector<String> SourceBuffer::bufferedSamplesForTrackID(const AtomicString& trackID)
1962 {
1963     auto it = m_trackBufferMap.find(trackID);
1964     if (it == m_trackBufferMap.end())
1965         return Vector<String>();
1966
1967     TrackBuffer& trackBuffer = it->value;
1968     Vector<String> sampleDescriptions;
1969     for (auto& pair : trackBuffer.samples.decodeOrder())
1970         sampleDescriptions.append(toString(*pair.second));
1971
1972     return sampleDescriptions;
1973 }
1974
1975 Document& SourceBuffer::document() const
1976 {
1977     ASSERT(scriptExecutionContext());
1978     return downcast<Document>(*scriptExecutionContext());
1979 }
1980
1981 void SourceBuffer::setMode(AppendMode newMode, ExceptionCode& ec)
1982 {
1983     // 3.1 Attributes - mode
1984     // http://www.w3.org/TR/media-source/#widl-SourceBuffer-mode
1985
1986     // On setting, run the following steps:
1987
1988     // 1. Let new mode equal the new value being assigned to this attribute.
1989     // 2. If generate timestamps flag equals true and new mode equals "segments", then throw an INVALID_ACCESS_ERR exception and abort these steps.
1990     if (m_shouldGenerateTimestamps && newMode == AppendMode::Segments) {
1991         ec = INVALID_ACCESS_ERR;
1992         return;
1993     }
1994
1995     // 3. If this object has been removed from the sourceBuffers attribute of the parent media source, then throw an INVALID_STATE_ERR exception and abort these steps.
1996     // 4. If the updating attribute equals true, then throw an INVALID_STATE_ERR exception and abort these steps.
1997     if (isRemoved() || m_updating) {
1998         ec = INVALID_STATE_ERR;
1999         return;
2000     }
2001
2002     // 5. If the readyState attribute of the parent media source is in the "ended" state then run the following steps:
2003     if (m_source->readyState() == MediaSource::endedKeyword()) {
2004         // 5.1. Set the readyState attribute of the parent media source to "open"
2005         // 5.2. Queue a task to fire a simple event named sourceopen at the parent media source.
2006         m_source->openIfInEndedState();
2007     }
2008
2009     // 6. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
2010     if (m_appendState == ParsingMediaSegment) {
2011         ec = INVALID_STATE_ERR;
2012         return;
2013     }
2014
2015     // 7. If the new mode equals "sequence", then set the group start timestamp to the group end timestamp.
2016     if (newMode == AppendMode::Sequence)
2017         m_groupStartTimestamp = m_groupEndTimestamp;
2018
2019     // 8. Update the attribute to new mode.
2020     m_mode = newMode;
2021 }
2022
2023 } // namespace WebCore
2024
2025 #endif