[MSE] Add MediaSource extensions to AudioTrack, VideoTrack, and TextTrack.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Nov 2013 05:26:23 +0000 (05:26 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Nov 2013 05:26:23 +0000 (05:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123374

Reviewed by Eric Carlson.

No tests added; tests will be added when Mock implementations are added in a future patch.

Add new partial interfaces for added methods on AudioTrack, TextTrack, and VideoTrack:
* Modules/mediasource/AudioTrackMediaSource.idl: Add read-only sourceBuffer attribute.
* Modules/mediasource/TextTrackMediaSource.idl: Ditto.
* Modules/mediasource/VideoTrackMediaSource.idl: Ditto.
* Modules/mediasource/AudioTrackMediaSource.h:
(WebCore::AudioTrackMediaSource::sourceBuffer): Added static wrapper around non-static sourceBuffer().
* Modules/mediasource/TextTrackMediaSource.h:
(WebCore::TextTrackMediaSource::sourceBuffer): Ditto.
* Modules/mediasource/VideoTrackMediaSource.h:
(WebCore::VideoTrackMediaSource::sourceBuffer): Ditto.

Add support for writable kind & language attributes through a custom setter:
* bindings/js/JSAudioTrackCustom.cpp:
(WebCore::JSAudioTrack::setKind):
(WebCore::JSAudioTrack::setLanguage):
* bindings/js/JSTextTrackCustom.cpp:
(WebCore::JSTextTrack::setKind):
(WebCore::JSTextTrack::setLanguage):
* bindings/js/JSVideoTrackCustom.cpp:
(WebCore::JSVideoTrack::setKind):
(WebCore::JSVideoTrack::setLanguage):
* html/track/AudioTrack.idl:
* html/track/TextTrack.idl:
* html/track/VideoTrack.idl:

Add setter methods to the implementation classes:
* html/track/TextTrack.cpp:
(WebCore::TextTrack::TextTrack):
(WebCore::TextTrack::setKind):
(WebCore::TextTrack::setLanguage):
* html/track/TextTrack.h:
* html/track/TrackBase.cpp:
(WebCore::TrackBase::TrackBase):
(WebCore::TrackBase::setKind):
(WebCore::TrackBase::setKindInternal):
* html/track/TrackBase.h:
(WebCore::TrackBase::setLanguage):
(WebCore::TrackBase::sourceBuffer):
(WebCore::TrackBase::setSourceBuffer):
* html/track/VideoTrack.cpp:
(WebCore::VideoTrack::VideoTrack):
(WebCore::VideoTrack::setKind):
(WebCore::VideoTrack::setLanguage):
* html/track/VideoTrack.h:

Implement the unimplemented portions of MediaSource and SourceBuffer:
* Modules/mediasource/MediaSource.cpp:
(WebCore::MediaSource::removeSourceBuffer):
* Modules/mediasource/MediaSourceBase.cpp:
(WebCore::MediaSourceBase::MediaSourceBase):
(WebCore::MediaSourceBase::setPrivateAndOpen):
(WebCore::MediaSourceBase::setReadyState):
(WebCore::MediaSourceBase::attachToElement):
* Modules/mediasource/MediaSourceBase.h:
(WebCore::MediaSourceBase::mediaElement):
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::videoTracks):
(WebCore::SourceBuffer::audioTracks):
(WebCore::SourceBuffer::textTracks):
(WebCore::SourceBuffer::sourceBufferPrivateDidAddAudioTrack):
(WebCore::SourceBuffer::sourceBufferPrivateDidAddVideoTrack):
(WebCore::SourceBuffer::sourceBufferPrivateDidAddTextTrack):
(WebCore::SourceBuffer::sourceBufferPrivateDidChangeActiveState):
* Modules/mediasource/SourceBuffer.h:
* Modules/mediasource/SourceBuffer.idl:

Add new files to the project:
* DerivedSources.make:
* WebCore.xcodeproj/project.pbxproj:

And a smorgasbord of other utility changes:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::loadResource): Pass this when attaching.
(WebCore::HTMLMediaElement::mediaPlayerDidAddTextTrack): Ditto.
* html/HTMLMediaSource.h:
* html/track/TextTrackList.cpp:
(TextTrackList::item): Make const.
* html/track/TextTrackList.h:
(WebCore::TextTrackList::lastItem): Added.
* platform/graphics/InbandTextTrackPrivate.h:
(WebCore::InbandTextTrackPrivate::create): Added.
(WebCore::MockSourceBufferPrivate::trackDidChangeEnabled):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@158821 268f45cc-cd09-0410-ab3c-d52691b4dbfc

43 files changed:
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/mediasource/AudioTrackMediaSource.h [new file with mode: 0644]
Source/WebCore/Modules/mediasource/AudioTrackMediaSource.idl [new file with mode: 0644]
Source/WebCore/Modules/mediasource/MediaSource.cpp
Source/WebCore/Modules/mediasource/MediaSource.h
Source/WebCore/Modules/mediasource/MediaSourceBase.cpp
Source/WebCore/Modules/mediasource/MediaSourceBase.h
Source/WebCore/Modules/mediasource/SourceBuffer.cpp
Source/WebCore/Modules/mediasource/SourceBuffer.h
Source/WebCore/Modules/mediasource/SourceBuffer.idl
Source/WebCore/Modules/mediasource/SourceBufferList.h
Source/WebCore/Modules/mediasource/TextTrackMediaSource.h [new file with mode: 0644]
Source/WebCore/Modules/mediasource/TextTrackMediaSource.idl [new file with mode: 0644]
Source/WebCore/Modules/mediasource/VideoTrackMediaSource.h [new file with mode: 0644]
Source/WebCore/Modules/mediasource/VideoTrackMediaSource.idl [new file with mode: 0644]
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSAudioTrackCustom.cpp
Source/WebCore/bindings/js/JSTextTrackCustom.cpp
Source/WebCore/bindings/js/JSVideoTrackCustom.cpp
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaSource.h
Source/WebCore/html/TimeRanges.cpp
Source/WebCore/html/TimeRanges.h
Source/WebCore/html/track/AudioTrack.h
Source/WebCore/html/track/AudioTrack.idl
Source/WebCore/html/track/TextTrack.cpp
Source/WebCore/html/track/TextTrack.h
Source/WebCore/html/track/TextTrack.idl
Source/WebCore/html/track/TextTrackList.cpp
Source/WebCore/html/track/TextTrackList.h
Source/WebCore/html/track/TrackBase.cpp
Source/WebCore/html/track/TrackBase.h
Source/WebCore/html/track/TrackListBase.cpp
Source/WebCore/html/track/TrackListBase.h
Source/WebCore/html/track/VideoTrack.cpp
Source/WebCore/html/track/VideoTrack.h
Source/WebCore/html/track/VideoTrack.idl
Source/WebCore/platform/MediaDescription.h [new file with mode: 0644]
Source/WebCore/platform/MediaSample.h [new file with mode: 0644]
Source/WebCore/platform/graphics/InbandTextTrackPrivate.h
Source/WebCore/platform/graphics/MediaSourcePrivate.h
Source/WebCore/platform/graphics/SourceBufferPrivate.h

index 150880f..e13930c 100644 (file)
@@ -1,3 +1,95 @@
+2013-10-25  Jer Noble  <jer.noble@apple.com>
+
+        [MSE] Add MediaSource extensions to AudioTrack, VideoTrack, and TextTrack.
+        https://bugs.webkit.org/show_bug.cgi?id=123374
+
+        Reviewed by Eric Carlson.
+
+        No tests added; tests will be added when Mock implementations are added in a future patch.
+
+        Add new partial interfaces for added methods on AudioTrack, TextTrack, and VideoTrack:
+        * Modules/mediasource/AudioTrackMediaSource.idl: Add read-only sourceBuffer attribute.
+        * Modules/mediasource/TextTrackMediaSource.idl: Ditto.
+        * Modules/mediasource/VideoTrackMediaSource.idl: Ditto.
+        * Modules/mediasource/AudioTrackMediaSource.h:
+        (WebCore::AudioTrackMediaSource::sourceBuffer): Added static wrapper around non-static sourceBuffer().
+        * Modules/mediasource/TextTrackMediaSource.h:
+        (WebCore::TextTrackMediaSource::sourceBuffer): Ditto.
+        * Modules/mediasource/VideoTrackMediaSource.h:
+        (WebCore::VideoTrackMediaSource::sourceBuffer): Ditto.
+
+        Add support for writable kind & language attributes through a custom setter:
+        * bindings/js/JSAudioTrackCustom.cpp:
+        (WebCore::JSAudioTrack::setKind):
+        (WebCore::JSAudioTrack::setLanguage):
+        * bindings/js/JSTextTrackCustom.cpp:
+        (WebCore::JSTextTrack::setKind):
+        (WebCore::JSTextTrack::setLanguage):
+        * bindings/js/JSVideoTrackCustom.cpp:
+        (WebCore::JSVideoTrack::setKind):
+        (WebCore::JSVideoTrack::setLanguage):
+        * html/track/AudioTrack.idl:
+        * html/track/TextTrack.idl:
+        * html/track/VideoTrack.idl:
+
+        Add setter methods to the implementation classes:
+        * html/track/TextTrack.cpp:
+        (WebCore::TextTrack::TextTrack):
+        (WebCore::TextTrack::setKind):
+        (WebCore::TextTrack::setLanguage):
+        * html/track/TextTrack.h:
+        * html/track/TrackBase.cpp:
+        (WebCore::TrackBase::TrackBase):
+        (WebCore::TrackBase::setKind):
+        (WebCore::TrackBase::setKindInternal):
+        * html/track/TrackBase.h:
+        (WebCore::TrackBase::setLanguage):
+        (WebCore::TrackBase::sourceBuffer):
+        (WebCore::TrackBase::setSourceBuffer):
+        * html/track/VideoTrack.cpp:
+        (WebCore::VideoTrack::VideoTrack):
+        (WebCore::VideoTrack::setKind):
+        (WebCore::VideoTrack::setLanguage):
+        * html/track/VideoTrack.h:
+
+        Implement the unimplemented portions of MediaSource and SourceBuffer:
+        * Modules/mediasource/MediaSource.cpp:
+        (WebCore::MediaSource::removeSourceBuffer):
+        * Modules/mediasource/MediaSourceBase.cpp:
+        (WebCore::MediaSourceBase::MediaSourceBase):
+        (WebCore::MediaSourceBase::setPrivateAndOpen):
+        (WebCore::MediaSourceBase::setReadyState):
+        (WebCore::MediaSourceBase::attachToElement):
+        * Modules/mediasource/MediaSourceBase.h:
+        (WebCore::MediaSourceBase::mediaElement):
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::videoTracks):
+        (WebCore::SourceBuffer::audioTracks):
+        (WebCore::SourceBuffer::textTracks):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidAddAudioTrack):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidAddVideoTrack):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidAddTextTrack):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidChangeActiveState):
+        * Modules/mediasource/SourceBuffer.h:
+        * Modules/mediasource/SourceBuffer.idl:
+
+        Add new files to the project:
+        * DerivedSources.make:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        And a smorgasbord of other utility changes:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::loadResource): Pass this when attaching.
+        (WebCore::HTMLMediaElement::mediaPlayerDidAddTextTrack): Ditto.
+        * html/HTMLMediaSource.h:
+        * html/track/TextTrackList.cpp:
+        (TextTrackList::item): Make const.
+        * html/track/TextTrackList.h:
+        (WebCore::TextTrackList::lastItem): Added.
+        * platform/graphics/InbandTextTrackPrivate.h:
+        (WebCore::InbandTextTrackPrivate::create): Added.
+        (WebCore::MockSourceBufferPrivate::trackDidChangeEnabled):
+
 2013-11-06  Vani Hegde  <vani.hegde@samsung.com>
 
         Applied background color is not retained after typing a characters
index dd1f067..f6d1cc0 100644 (file)
@@ -94,9 +94,14 @@ BINDING_IDLS = \
     $(WebCore)/Modules/indieui/UIRequestEvent.idl \
     $(WebCore)/Modules/mediacontrols/MediaControlsHost.idl \
        $(WebCore)/Modules/mediasource/DOMURLMediaSource.idl \
+       $(WebCore)/Modules/mediasource/AudioTrackMediaSource.idl \
        $(WebCore)/Modules/mediasource/MediaSource.idl \
        $(WebCore)/Modules/mediasource/SourceBuffer.idl \
        $(WebCore)/Modules/mediasource/SourceBufferList.idl \
+    $(WebCore)/Modules/mediasource/SourceBuffer.idl \
+    $(WebCore)/Modules/mediasource/SourceBufferList.idl \
+       $(WebCore)/Modules/mediasource/TextTrackMediaSource.idl \
+       $(WebCore)/Modules/mediasource/VideoTrackMediaSource.idl \
        $(WebCore)/Modules/mediastream/AllVideoCapabilities.idl \
        $(WebCore)/Modules/mediastream/AllAudioCapabilities.idl \
        $(WebCore)/Modules/mediastream/AudioStreamTrack.idl \
diff --git a/Source/WebCore/Modules/mediasource/AudioTrackMediaSource.h b/Source/WebCore/Modules/mediasource/AudioTrackMediaSource.h
new file mode 100644 (file)
index 0000000..af1ab97
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef AudioTrackMediaSource_h
+#define AudioTrackMediaSource_h
+
+#if ENABLE(MEDIA_SOURCE) && ENABLE(VIDEO_TRACK)
+
+#include "AudioTrack.h"
+
+namespace WebCore {
+
+class SourceBuffer;
+
+class AudioTrackMediaSource {
+public:
+    static SourceBuffer* sourceBuffer(AudioTrack* track) { return track->sourceBuffer(); }
+};
+
+}
+
+#endif
+
+
+#endif
diff --git a/Source/WebCore/Modules/mediasource/AudioTrackMediaSource.idl b/Source/WebCore/Modules/mediasource/AudioTrackMediaSource.idl
new file mode 100644 (file)
index 0000000..f91cb4a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+[
+    Conditional=MEDIA_SOURCE&VIDEO_TRACK,
+]
+partial interface AudioTrack {
+    readonly attribute SourceBuffer sourceBuffer;
+};
index 5b3ff40..d334437 100644 (file)
 
 #if ENABLE(MEDIA_SOURCE)
 
+#include "AudioTrack.h"
+#include "AudioTrackList.h"
 #include "ContentType.h"
 #include "ExceptionCodePlaceholder.h"
 #include "GenericEventQueue.h"
+#include "HTMLMediaElement.h"
 #include "Logging.h"
 #include "MIMETypeRegistry.h"
 #include "MediaPlayer.h"
 #include "MediaSourceRegistry.h"
 #include "SourceBufferPrivate.h"
+#include "TextTrack.h"
+#include "TextTrackList.h"
 #include "TimeRanges.h"
+#include "VideoTrack.h"
+#include "VideoTrackList.h"
 #include <runtime/Uint8Array.h>
 #include <wtf/text/CString.h>
 
@@ -136,8 +143,126 @@ void MediaSource::removeSourceBuffer(SourceBuffer* buffer, ExceptionCode& ec)
     // 3. If the sourceBuffer.updating attribute equals true, then run the following steps: ...
     buffer->abortIfUpdating();
 
-    // Steps 4-9 are related to updating audioTracks, videoTracks, and textTracks which aren't implmented yet.
-    // FIXME(91649): support track selection
+    // 4. Let SourceBuffer audioTracks list equal the AudioTrackList object returned by sourceBuffer.audioTracks.
+    RefPtr<AudioTrackList> audioTracks = buffer->audioTracks();
+
+    // 5. If the SourceBuffer audioTracks list is not empty, then run the following steps:
+    if (audioTracks->length()) {
+        // 5.1 Let HTMLMediaElement audioTracks list equal the AudioTrackList object returned by the audioTracks
+        // attribute on the HTMLMediaElement.
+        // 5.2 Let the removed enabled audio track flag equal false.
+        bool removedEnabledAudioTrack = false;
+
+        // 5.3 For each AudioTrack object in the SourceBuffer audioTracks list, run the following steps:
+        while (audioTracks->length()) {
+            AudioTrack* track = audioTracks->lastItem();
+
+            // 5.3.1 Set the sourceBuffer attribute on the AudioTrack object to null.
+            track->setSourceBuffer(0);
+
+            // 5.3.2 If the enabled attribute on the AudioTrack object is true, then set the removed enabled
+            // audio track flag to true.
+            if (track->enabled())
+                removedEnabledAudioTrack = true;
+
+            // 5.3.3 Remove the AudioTrack object from the HTMLMediaElement audioTracks list.
+            // 5.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement audioTracks list.
+            if (mediaElement())
+                mediaElement()->removeAudioTrack(track);
+
+            // 5.3.5 Remove the AudioTrack object from the SourceBuffer audioTracks list.
+            // 5.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer audioTracks list.
+            audioTracks->remove(track);
+        }
+
+        // 5.4 If the removed enabled audio track flag equals true, then queue a task to fire a simple event
+        // named change at the HTMLMediaElement audioTracks list.
+        if (removedEnabledAudioTrack)
+            mediaElement()->audioTracks()->scheduleChangeEvent();
+    }
+
+    // 6. Let SourceBuffer videoTracks list equal the VideoTrackList object returned by sourceBuffer.videoTracks.
+    RefPtr<VideoTrackList> videoTracks = buffer->videoTracks();
+
+    // 7. If the SourceBuffer videoTracks list is not empty, then run the following steps:
+    if (videoTracks->length()) {
+        // 7.1 Let HTMLMediaElement videoTracks list equal the VideoTrackList object returned by the videoTracks
+        // attribute on the HTMLMediaElement.
+        // 7.2 Let the removed selected video track flag equal false.
+        bool removedSelectedVideoTrack = false;
+
+        // 7.3 For each VideoTrack object in the SourceBuffer videoTracks list, run the following steps:
+        while (videoTracks->length()) {
+            VideoTrack* track = videoTracks->lastItem();
+
+            // 7.3.1 Set the sourceBuffer attribute on the VideoTrack object to null.
+            track->setSourceBuffer(0);
+
+            // 7.3.2 If the selected attribute on the VideoTrack object is true, then set the removed selected
+            // video track flag to true.
+            if (track->selected())
+                removedSelectedVideoTrack = true;
+
+            // 7.3.3 Remove the VideoTrack object from the HTMLMediaElement videoTracks list.
+            // 7.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement videoTracks list.
+            if (mediaElement())
+                mediaElement()->removeVideoTrack(track);
+
+            // 7.3.5 Remove the VideoTrack object from the SourceBuffer videoTracks list.
+            // 7.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer videoTracks list.
+            videoTracks->remove(track);
+        }
+
+        // 7.4 If the removed selected video track flag equals true, then queue a task to fire a simple event
+        // named change at the HTMLMediaElement videoTracks list.
+        if (removedSelectedVideoTrack)
+            mediaElement()->videoTracks()->scheduleChangeEvent();
+    }
+
+    // 8. Let SourceBuffer textTracks list equal the TextTrackList object returned by sourceBuffer.textTracks.
+    RefPtr<TextTrackList> textTracks = buffer->textTracks();
+
+    // 9. If the SourceBuffer textTracks list is not empty, then run the following steps:
+    if (textTracks->length()) {
+        // 9.1 Let HTMLMediaElement textTracks list equal the TextTrackList object returned by the textTracks
+        // attribute on the HTMLMediaElement.
+        // 9.2 Let the removed enabled text track flag equal false.
+        bool removedEnabledTextTrack = false;
+
+        // 9.3 For each TextTrack object in the SourceBuffer textTracks list, run the following steps:
+        while (textTracks->length()) {
+            TextTrack* track = textTracks->lastItem();
+
+            // 9.3.1 Set the sourceBuffer attribute on the TextTrack object to null.
+            track->setSourceBuffer(0);
+
+            // 9.3.2 If the mode attribute on the TextTrack object is set to "showing" or "hidden", then
+            // set the removed enabled text track flag to true.
+            if (track->mode() == TextTrack::showingKeyword() || track->mode() == TextTrack::hiddenKeyword())
+                removedEnabledTextTrack = true;
+
+            // 9.3.3 Remove the TextTrack object from the HTMLMediaElement textTracks list.
+            // 9.3.4 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the HTMLMediaElement textTracks list.
+            if (mediaElement())
+                mediaElement()->removeTextTrack(track);
+
+            // 9.3.5 Remove the TextTrack object from the SourceBuffer textTracks list.
+            // 9.3.6 Queue a task to fire a trusted event named removetrack, that does not bubble and is not
+            // cancelable, and that uses the TrackEvent interface, at the SourceBuffer textTracks list.
+            textTracks->remove(track);
+        }
+
+        // 9.4 If the removed enabled text track flag equals true, then queue a task to fire a simple event
+        // named change at the HTMLMediaElement textTracks list.
+        if (removedEnabledTextTrack)
+            mediaElement()->textTracks()->scheduleChangeEvent();
+    }
+
 
     // 10. If sourceBuffer is in activeSourceBuffers, then remove sourceBuffer from activeSourceBuffers ...
     m_activeSourceBuffers->remove(buffer);
@@ -216,6 +341,118 @@ EventTargetInterface MediaSource::eventTargetInterface() const
     return MediaSourceEventTargetInterfaceType;
 }
 
+void MediaSource::sourceBufferDidChangeAcitveState(SourceBuffer* sourceBuffer, bool active)
+{
+    if (active && !m_activeSourceBuffers->contains(sourceBuffer))
+        m_activeSourceBuffers->add(sourceBuffer);
+    else if (!active && m_activeSourceBuffers->contains(sourceBuffer))
+        m_activeSourceBuffers->remove(sourceBuffer);
+}
+
+class SourceBufferBufferedDoesNotContainTime {
+public:
+    SourceBufferBufferedDoesNotContainTime(double time) : m_time(time) { }
+    bool operator()(RefPtr<SourceBuffer> sourceBuffer)
+    {
+        return !sourceBuffer->buffered()->contain(m_time);
+    }
+
+    double m_time;
+};
+
+class SourceBufferBufferedHasEnough {
+public:
+    SourceBufferBufferedHasEnough(double time, double duration) : m_time(time), m_duration(duration) { }
+    bool operator()(RefPtr<SourceBuffer> sourceBuffer)
+    {
+        size_t rangePos = sourceBuffer->buffered()->find(m_time);
+        if (rangePos == notFound)
+            return false;
+
+        double endTime = sourceBuffer->buffered()->end(rangePos, IGNORE_EXCEPTION);
+        return m_duration - endTime < 1;
+    }
+
+    double m_time;
+    double m_duration;
+};
+
+class SourceBufferBufferedHasFuture {
+public:
+    SourceBufferBufferedHasFuture(double time) : m_time(time) { }
+    bool operator()(RefPtr<SourceBuffer> sourceBuffer)
+    {
+        size_t rangePos = sourceBuffer->buffered()->find(m_time);
+        if (rangePos == notFound)
+            return false;
+
+        double endTime = sourceBuffer->buffered()->end(rangePos, IGNORE_EXCEPTION);
+        return endTime - m_time > 1;
+    }
+
+    double m_time;
+};
+
+void MediaSource::monitorSourceBuffers()
+{
+    double currentTime = mediaElement()->currentTime();
+
+    // 2.4.4 SourceBuffer Monitoring
+    // ↳ If buffered for all objects in activeSourceBuffers do not contain TimeRanges for the current
+    // playback position:
+    auto begin = m_activeSourceBuffers->begin();
+    auto end = m_activeSourceBuffers->end();
+    if (std::all_of(begin, end, SourceBufferBufferedDoesNotContainTime(currentTime))) {
+        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_METADATA.
+        // 2. If this is the first transition to HAVE_METADATA, then queue a task to fire a simple event
+        // named loadedmetadata at the media element.
+        m_private->setReadyState(MediaPlayer::HaveMetadata);
+
+        // 3. Abort these steps.
+        return;
+    }
+
+    // ↳ If buffered for all objects in activeSourceBuffers contain TimeRanges that include the current
+    // playback position and enough data to ensure uninterrupted playback:
+    if (std::all_of(begin, end, SourceBufferBufferedHasEnough(currentTime, mediaElement()->duration()))) {
+        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_ENOUGH_DATA.
+        // 2. Queue a task to fire a simple event named canplaythrough at the media element.
+        // 3. Playback may resume at this point if it was previously suspended by a transition to HAVE_CURRENT_DATA.
+        m_private->setReadyState(MediaPlayer::HaveEnoughData);
+
+        // 4. Abort these steps.
+        return;
+    }
+
+    // ↳ If buffered for at least one object in activeSourceBuffers contains a TimeRange that includes
+    // the current playback position but not enough data to ensure uninterrupted playback:
+    if (std::any_of(begin, end, SourceBufferBufferedHasFuture(currentTime))) {
+        // 1. Set the HTMLMediaElement.readyState attribute to HAVE_FUTURE_DATA.
+        // 2. If the previous value of HTMLMediaElement.readyState was less than HAVE_FUTURE_DATA, then queue a task to fire a simple event named canplay at the media element.
+        // 3. Playback may resume at this point if it was previously suspended by a transition to HAVE_CURRENT_DATA.
+        m_private->setReadyState(MediaPlayer::HaveFutureData);
+
+        // 4. Abort these steps.
+        return;
+    }
+
+    // ↳ If buffered for at least one object in activeSourceBuffers contains a TimeRange that ends
+    // at the current playback position and does not have a range covering the time immediately
+    // after the current position:
+    // NOTE: Logically, !(all objects do not contain currentTime) == (some objects contain current time)
+
+    // 1. Set the HTMLMediaElement.readyState attribute to HAVE_CURRENT_DATA.
+    // 2. If this is the first transition to HAVE_CURRENT_DATA, then queue a task to fire a simple
+    // event named loadeddata at the media element.
+    // 3. Playback is suspended at this point since the media element doesn't have enough data to
+    // advance the media timeline.
+    m_private->setReadyState(MediaPlayer::HaveCurrentData);
+
+    // 4. Abort these steps.
+}
+
+
+
 } // namespace WebCore
 
 #endif
index 066db6d..67d5f3c 100644 (file)
@@ -59,6 +59,10 @@ public:
     using RefCounted<MediaSourceBase>::ref;
     using RefCounted<MediaSourceBase>::deref;
 
+    void sourceBufferDidChangeAcitveState(SourceBuffer*, bool);
+
+    void monitorSourceBuffers();
+
 private:
     explicit MediaSource(ScriptExecutionContext&);
 
index c4e1d84..f1e46ef 100644 (file)
@@ -47,9 +47,9 @@ namespace WebCore {
 
 MediaSourceBase::MediaSourceBase(ScriptExecutionContext& context)
     : ActiveDOMObject(&context)
+    , m_mediaElement(0)
     , m_readyState(closedKeyword())
     , m_asyncEventQueue(*this)
-    , m_attached(false)
 {
 }
 
@@ -78,7 +78,7 @@ const AtomicString& MediaSourceBase::endedKeyword()
 void MediaSourceBase::setPrivateAndOpen(PassRef<MediaSourcePrivate> mediaSourcePrivate)
 {
     ASSERT(!m_private);
-    ASSERT(m_attached);
+    ASSERT(m_mediaElement);
     m_private = std::move(mediaSourcePrivate);
     setReadyState(openKeyword());
 }
@@ -165,7 +165,7 @@ void MediaSourceBase::setReadyState(const AtomicString& state)
 
     if (state == closedKeyword()) {
         m_private.clear();
-        m_attached = false;
+        m_mediaElement = 0;
     }
 
     if (oldState == state)
@@ -222,14 +222,14 @@ void MediaSourceBase::close()
     setReadyState(closedKeyword());
 }
 
-bool MediaSourceBase::attachToElement()
+bool MediaSourceBase::attachToElement(HTMLMediaElement* element)
 {
-    if (m_attached)
+    if (m_mediaElement)
         return false;
 
     ASSERT(isClosed());
 
-    m_attached = true;
+    m_mediaElement = element;
     return true;
 }
 
index 1e38946..098fc49 100644 (file)
@@ -61,7 +61,7 @@ public:
     bool isOpen() const;
 
     // HTMLMediaSource
-    virtual bool attachToElement() OVERRIDE;
+    virtual bool attachToElement(HTMLMediaElement*) OVERRIDE;
     virtual void setPrivateAndOpen(PassRef<MediaSourcePrivate>) OVERRIDE;
     virtual void close() OVERRIDE;
     virtual bool isClosed() const OVERRIDE;
@@ -75,6 +75,7 @@ public:
     void setReadyState(const AtomicString&);
     void endOfStream(const AtomicString& error, ExceptionCode&);
 
+    HTMLMediaElement* mediaElement() const { return m_mediaElement; }
 
     // ActiveDOMObject interface
     virtual bool hasPendingActivity() const OVERRIDE;
@@ -101,11 +102,10 @@ protected:
     void scheduleEvent(const AtomicString& eventName);
     GenericEventQueue& asyncEventQueue() { return m_asyncEventQueue; }
 
-private:
     RefPtr<MediaSourcePrivate> m_private;
+    HTMLMediaElement* m_mediaElement;
     AtomicString m_readyState;
     GenericEventQueue m_asyncEventQueue;
-    bool m_attached;
 };
 
 }
index 4578fe4..57f3e0b 100644 (file)
 
 #if ENABLE(MEDIA_SOURCE)
 
+#include "AudioTrackList.h"
 #include "Event.h"
 #include "GenericEventQueue.h"
 #include "HTMLMediaElement.h"
+#include "InbandTextTrack.h"
 #include "Logging.h"
+#include "MediaDescription.h"
+#include "MediaSample.h"
 #include "MediaSource.h"
 #include "SourceBufferPrivate.h"
+#include "TextTrackList.h"
 #include "TimeRanges.h"
+#include "VideoTrackList.h"
+#include <map>
+#include <wtf/NeverDestroyed.h>
 
 namespace WebCore {
 
+struct SourceBuffer::TrackBuffer {
+    MediaTime lastDecodeTimestamp;
+    MediaTime lastFrameDuration;
+    MediaTime highestPresentationTimestamp;
+    MediaTime lastEnqueuedPresentationTime;
+    bool needRandomAccessFlag;
+    typedef std::multimap<MediaTime, RefPtr<MediaSample>> SampleMap;
+    SampleMap samples;
+    SampleMap decodeQueue;
+    RefPtr<MediaDescription> description;
+
+    TrackBuffer()
+        : lastDecodeTimestamp(MediaTime::invalidTime())
+        , lastFrameDuration(MediaTime::invalidTime())
+        , highestPresentationTimestamp(MediaTime::invalidTime())
+        , lastEnqueuedPresentationTime(MediaTime::invalidTime())
+        , needRandomAccessFlag(false)
+    {
+    }
+};
+
 PassRef<SourceBuffer> SourceBuffer::create(PassRef<SourceBufferPrivate> sourceBufferPrivate, MediaSource* source)
 {
     RefPtr<SourceBuffer> sourceBuffer(adoptRef(new SourceBuffer(std::move(sourceBufferPrivate), source)));
@@ -56,8 +85,12 @@ SourceBuffer::SourceBuffer(PassRef<SourceBufferPrivate> sourceBufferPrivate, Med
     , m_source(source)
     , m_asyncEventQueue(*this)
     , m_updating(false)
-    , m_timestampOffset(0)
     , m_appendBufferTimer(this, &SourceBuffer::appendBufferTimerFired)
+    , m_highestPresentationEndTimestamp(MediaTime::invalidTime())
+    , m_receivedFirstInitializationSegment(false)
+    , m_buffered(TimeRanges::create())
+    , m_active(false)
+    , m_appendState(WaitingForSegment)
 {
     ASSERT(m_private);
     ASSERT(m_source);
@@ -83,12 +116,17 @@ PassRefPtr<TimeRanges> SourceBuffer::buffered(ExceptionCode& ec) const
     }
 
     // 2. Return a new static normalized TimeRanges object for the media segments buffered.
-    return m_private->buffered();
+    return m_buffered->copy();
+}
+
+const RefPtr<TimeRanges>& SourceBuffer::buffered() const
+{
+    return m_buffered;
 }
 
 double SourceBuffer::timestampOffset() const
 {
-    return m_timestampOffset;
+    return m_timestampOffset.toDouble();
 }
 
 void SourceBuffer::setTimestampOffset(double offset, ExceptionCode& ec)
@@ -112,9 +150,8 @@ void SourceBuffer::setTimestampOffset(double offset, ExceptionCode& ec)
     // 4.2 Queue a task to fire a simple event named sourceopen at the parent media source.
     m_source->openIfInEndedState();
 
-    // 5. If this object is waiting for the end of a media segment to be appended, then throw an INVALID_STATE_ERR
-    // and abort these steps.
-    if (!m_private->setTimestampOffset(offset)) {
+    // 5. If the append state equals PARSING_MEDIA_SEGMENT, then throw an INVALID_STATE_ERR and abort these steps.
+    if (m_appendState == ParsingMediaSegment) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -285,6 +322,62 @@ void SourceBuffer::appendBufferTimerFired(Timer<SourceBuffer>*)
 
     // 5. Queue a task to fire a simple event named updateend at this SourceBuffer object.
     scheduleEvent(eventNames().updateendEvent);
+
+    m_source->monitorSourceBuffers();
+}
+
+const AtomicString& SourceBuffer::decodeError()
+{
+    static NeverDestroyed<AtomicString> decode("decode", AtomicString::ConstructFromLiteral);
+    return decode;
+}
+
+const AtomicString& SourceBuffer::networkError()
+{
+    static NeverDestroyed<AtomicString> network("network", AtomicString::ConstructFromLiteral);
+    return network;
+}
+
+VideoTrackList* SourceBuffer::videoTracks()
+{
+    if (!m_source->mediaElement())
+        return 0;
+
+    if (!m_videoTracks)
+        m_videoTracks = VideoTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
+
+    return m_videoTracks.get();
+}
+
+AudioTrackList* SourceBuffer::audioTracks()
+{
+    if (!m_source->mediaElement())
+        return 0;
+
+    if (!m_audioTracks)
+        m_audioTracks = AudioTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
+
+    return m_audioTracks.get();
+}
+
+TextTrackList* SourceBuffer::textTracks()
+{
+    if (!m_source->mediaElement())
+        return 0;
+
+    if (!m_textTracks)
+        m_textTracks = TextTrackList::create(m_source->mediaElement(), ActiveDOMObject::scriptExecutionContext());
+
+    return m_textTracks.get();
+}
+
+void SourceBuffer::setActive(bool active)
+{
+    if (m_active == active)
+        return;
+
+    m_active = active;
+    m_source->sourceBufferDidChangeAcitveState(this, active);
 }
 
 void SourceBuffer::sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const WTF::AtomicString& error)
@@ -292,22 +385,621 @@ void SourceBuffer::sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const W
     m_source->endOfStream(error, IgnorableExceptionCode());
 }
 
-void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment&)
+void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment& segment)
 {
+    m_appendState = ParsingInitSegment;
+
+    // 3.5.7 Initialization Segment Received
+    // 1. Update the duration attribute if it currently equals NaN:
+    if (std::isnan(m_source->duration()) && segment.duration.isValid())
+        m_source->setDuration(segment.duration.toDouble(), IGNORE_EXCEPTION);
+
+    // 2. If the initialization segment has no audio, video, or text tracks, then run the end of stream
+    // algorithm with the error parameter set to "decode" and abort these steps.
+    if (!segment.audioTracks.size() && !segment.videoTracks.size() && !segment.textTracks.size())
+        m_source->endOfStream(decodeError(), IgnorableExceptionCode());
+
+
+    // 3. If the first initialization segment flag is true, then run the following steps:
+    if (m_receivedFirstInitializationSegment) {
+        if (!validateInitializationSegment(segment)) {
+            m_source->endOfStream(decodeError(), IgnorableExceptionCode());
+            return;
+        }
+        // 3.2 Add the appropriate track descriptions from this initialization segment to each of the track buffers.
+        // NOTE: No changes to make
+    }
+
+    // 4. Let active track flag equal false.
+    bool activeTrackFlag = false;
+
+    // 5. If the first initialization segment flag is false, then run the following steps:
+    if (!m_receivedFirstInitializationSegment) {
+        // 5.1 If the initialization segment contains tracks with codecs the user agent does not support,
+        // then run the end of stream algorithm with the error parameter set to "decode" and abort these steps.
+        // NOTE: This check is the responsibility of the SourceBufferPrivate.
+
+        // 5.2 For each audio track in the initialization segment, run following steps:
+        for (auto it = segment.audioTracks.begin(); it != segment.audioTracks.end(); ++it) {
+            AudioTrackPrivate* audioTrackPrivate = it->track.get();
+
+            // 5.2.1 Let new audio track be a new AudioTrack object.
+            // 5.2.2 Generate a unique ID and assign it to the id property on new video track.
+            RefPtr<AudioTrack> newAudioTrack = AudioTrack::create(this, audioTrackPrivate);
+            newAudioTrack->setSourceBuffer(this);
+
+            // 5.2.3 If audioTracks.length equals 0, then run the following steps:
+            if (!audioTracks()->length()) {
+                // 5.2.3.1 Set the enabled property on new audio track to true.
+                newAudioTrack->setEnabled(true);
+
+                // 5.2.3.2 Set active track flag to true.
+                activeTrackFlag = true;
+            }
+
+            // 5.2.4 Add new audio track to the audioTracks attribute on this SourceBuffer object.
+            // 5.2.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
+            // referenced by the audioTracks attribute on this SourceBuffer object.
+            audioTracks()->append(newAudioTrack);
+
+            // 5.2.6 Add new audio track to the audioTracks attribute on the HTMLMediaElement.
+            // 5.2.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object
+            // referenced by the audioTracks attribute on the HTMLMediaElement.
+            m_source->mediaElement()->audioTracks()->append(newAudioTrack);
+
+            // 5.2.8 Create a new track buffer to store coded frames for this track.
+            ASSERT(!m_trackBufferMap.contains(newAudioTrack->id()));
+            TrackBuffer& trackBuffer = m_trackBufferMap.add(newAudioTrack->id(), TrackBuffer()).iterator->value;
+
+            // 5.2.9 Add the track description for this track to the track buffer.
+            trackBuffer.description = it->description;
+        }
+
+        // 5.3 For each video track in the initialization segment, run following steps:
+        for (auto it = segment.videoTracks.begin(); it != segment.videoTracks.end(); ++it) {
+            VideoTrackPrivate* videoTrackPrivate = it->track.get();
+
+            // 5.3.1 Let new video track be a new VideoTrack object.
+            // 5.3.2 Generate a unique ID and assign it to the id property on new video track.
+            RefPtr<VideoTrack> newVideoTrack = VideoTrack::create(this, videoTrackPrivate);
+            newVideoTrack->setSourceBuffer(this);
+
+            // 5.3.3 If videoTracks.length equals 0, then run the following steps:
+            if (!videoTracks()->length()) {
+                // 5.3.3.1 Set the selected property on new video track to true.
+                newVideoTrack->setSelected(true);
+
+                // 5.3.3.2 Set active track flag to true.
+                activeTrackFlag = true;
+            }
+
+            // 5.3.4 Add new video track to the videoTracks attribute on this SourceBuffer object.
+            // 5.3.5 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
+            // referenced by the videoTracks attribute on this SourceBuffer object.
+            videoTracks()->append(newVideoTrack);
+
+            // 5.3.6 Add new video track to the videoTracks attribute on the HTMLMediaElement.
+            // 5.3.7 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object
+            // referenced by the videoTracks attribute on the HTMLMediaElement.
+            m_source->mediaElement()->videoTracks()->append(newVideoTrack);
+
+            // 5.3.8 Create a new track buffer to store coded frames for this track.
+            ASSERT(!m_trackBufferMap.contains(newVideoTrack->id()));
+            TrackBuffer& trackBuffer = m_trackBufferMap.add(newVideoTrack->id(), TrackBuffer()).iterator->value;
+
+            // 5.3.9 Add the track description for this track to the track buffer.
+            trackBuffer.description = it->description;
+        }
+
+        // 5.4 For each text track in the initialization segment, run following steps:
+        for (auto it = segment.textTracks.begin(); it != segment.textTracks.end(); ++it) {
+            InbandTextTrackPrivate* textTrackPrivate = it->track.get();
+
+            // 5.4.1 Let new text track be a new TextTrack object with its properties populated with the
+            // appropriate information from the initialization segment.
+            RefPtr<InbandTextTrack> newTextTrack = InbandTextTrack::create(scriptExecutionContext(), this, textTrackPrivate);
+
+            // 5.4.2 If the mode property on new text track equals "showing" or "hidden", then set active
+            // track flag to true.
+            if (textTrackPrivate->mode() != InbandTextTrackPrivate::Disabled)
+                activeTrackFlag = true;
+
+            // 5.4.3 Add new text track to the textTracks attribute on this SourceBuffer object.
+            // 5.4.4 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at textTracks attribute on this
+            // SourceBuffer object.
+            textTracks()->append(newTextTrack);
+
+            // 5.4.5 Add new text track to the textTracks attribute on the HTMLMediaElement.
+            // 5.4.6 Queue a task to fire a trusted event named addtrack, that does not bubble and is
+            // not cancelable, and that uses the TrackEvent interface, at the TextTrackList object
+            // referenced by the textTracks attribute on the HTMLMediaElement.
+            m_source->mediaElement()->textTracks()->append(newTextTrack);
+
+            // 5.4.7 Create a new track buffer to store coded frames for this track.
+            ASSERT(!m_trackBufferMap.contains(textTrackPrivate->id()));
+            TrackBuffer& trackBuffer = m_trackBufferMap.add(textTrackPrivate->id(), TrackBuffer()).iterator->value;
+
+            // 5.4.8 Add the track description for this track to the track buffer.
+            trackBuffer.description = it->description;
+        }
+
+        // 5.5 If active track flag equals true, then run the following steps:
+        if (activeTrackFlag) {
+            // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
+            setActive(true);
+        }
+
+        // 5.6 Set first initialization segment flag to true.
+        m_receivedFirstInitializationSegment = true;
+    }
+
+    // 6. If the HTMLMediaElement.readyState attribute is HAVE_NOTHING, then run the following steps:
+    if (m_private->readyState() == MediaPlayer::HaveNothing) {
+        // 6.1 If one or more objects in sourceBuffers have first initialization segment flag set to false, then abort these steps.
+        for (unsigned long i = 0; i < m_source->sourceBuffers()->length(); ++i) {
+            if (!m_source->sourceBuffers()->item(i)->m_receivedFirstInitializationSegment)
+                return;
+        }
+
+        // 6.2 Set the HTMLMediaElement.readyState attribute to HAVE_METADATA.
+        // 6.3 Queue a task to fire a simple event named loadedmetadata at the media element.
+        m_private->setReadyState(MediaPlayer::HaveMetadata);
+    }
+
+    // 7. If the active track flag equals true and the HTMLMediaElement.readyState
+    // attribute is greater than HAVE_CURRENT_DATA, then set the HTMLMediaElement.readyState
+    // attribute to HAVE_METADATA.
+    if (activeTrackFlag && m_private->readyState() > MediaPlayer::HaveCurrentData)
+        m_private->setReadyState(MediaPlayer::HaveMetadata);
 }
 
-void SourceBuffer::sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample>)
+bool SourceBuffer::validateInitializationSegment(const InitializationSegment& segment)
 {
+    // 3.1. Verify the following properties. If any of the checks fail then run the end of stream
+    // algorithm with the error parameter set to "decode" and abort these steps.
+    //   * The number of audio, video, and text tracks match what was in the first initialization segment.
+    if (segment.audioTracks.size() != audioTracks()->length()
+        || segment.videoTracks.size() != videoTracks()->length()
+        || segment.textTracks.size() != textTracks()->length())
+        return false;
+
+    //   * The codecs for each track, match what was specified in the first initialization segment.
+    for (auto it = segment.audioTracks.begin(); it != segment.audioTracks.end(); ++it) {
+        if (!m_videoCodecs.contains(it->description->codec()))
+            return false;
+    }
+
+    for (auto it = segment.videoTracks.begin(); it != segment.videoTracks.end(); ++it) {
+        if (!m_audioCodecs.contains(it->description->codec()))
+            return false;
+    }
+
+    for (auto it = segment.textTracks.begin(); it != segment.textTracks.end(); ++it) {
+        if (!m_textCodecs.contains(it->description->codec()))
+            return false;
+    }
+
+    //   * If more than one track for a single type are present (ie 2 audio tracks), then the Track
+    //   IDs match the ones in the first initialization segment.
+    if (segment.audioTracks.size() >= 2) {
+        for (auto it = segment.audioTracks.begin(); it != segment.audioTracks.end(); ++it) {
+            if (!m_trackBufferMap.contains(it->track->id()))
+                return false;
+        }
+    }
+
+    if (segment.videoTracks.size() >= 2) {
+        for (auto it = segment.videoTracks.begin(); it != segment.videoTracks.end(); ++it) {
+            if (!m_trackBufferMap.contains(it->track->id()))
+                return false;
+        }
+    }
+
+    if (segment.textTracks.size() >= 2) {
+        for (auto it = segment.videoTracks.begin(); it != segment.videoTracks.end(); ++it) {
+            if (!m_trackBufferMap.contains(it->track->id()))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+class SampleLessThanComparator {
+public:
+    bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
+    {
+        return value1.first < value2.first;
+    }
+
+    bool operator()(MediaTime value1, std::pair<MediaTime, RefPtr<MediaSample>> value2)
+    {
+        return value1 < value2.first;
+    }
+
+    bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value1, MediaTime value2)
+    {
+        return value1.first < value2;
+    }
+};
+
+class SampleContainsMediaTimeComparator {
+public:
+    bool contains(MediaSample* sample, MediaTime time)
+    {
+        MediaTime presentationStartTime = sample->presentationTime();
+        MediaTime presentationEndTime = presentationStartTime + sample->duration();
+        return presentationStartTime <= time && presentationEndTime > time;
+    }
+    bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value, MediaTime time)
+    {
+        MediaTime presentationStartTime = value.second->presentationTime();
+        MediaTime presentationEndTime = presentationStartTime + value.second->duration();
+        return presentationStartTime < time && presentationEndTime <= time;
+    }
+};
+
+class SamplePresentationTimeIsWithinRangeComparator {
+public:
+    bool operator()(std::pair<MediaTime, MediaTime> range, std::pair<MediaTime, RefPtr<MediaSample>> value)
+    {
+        return range.second < value.first;
+    }
+    bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value, std::pair<MediaTime, MediaTime> range)
+    {
+        return value.first < range.first;
+    }
+};
+
+class SampleIsRandomAccessPredicate {
+public:
+    bool operator()(std::pair<MediaTime, RefPtr<MediaSample>> value)
+    {
+        return value.second->flags() == MediaSample::IsSync;
+    }
+};
+
+void SourceBuffer::sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample> sample)
+{
+    // 3.5.8 Coded Frame Processing
+    // When complete coded frames have been parsed by the segment parser loop then the following steps
+    // are run:
+    // 1. For each coded frame in the media segment run the following steps:
+    // 1.1. Loop Top
+    do {
+        // 1.1 (ctd) Let presentation timestamp be a double precision floating point representation of
+        // the coded frame's presentation timestamp in seconds.
+        MediaTime presentationTimestamp = sample->presentationTime();
+
+        // 1.2 Let decode timestamp be a double precision floating point representation of the coded frame's
+        // decode timestamp in seconds.
+        MediaTime decodeTimestamp = sample->decodeTime();
+
+        // 1.3 Let frame duration be a double precision floating point representation of the coded frame's
+        // duration in seconds.
+        MediaTime frameDuration = sample->duration();
+
+        // 1.4 If mode equals "sequence" and group start timestamp is set, then run the following steps:
+        // FIXME: add support for "sequence" mode
+
+        // 1.5 If timestampOffset is not 0, then run the following steps:
+        if (m_timestampOffset != MediaTime::zeroTime()) {
+            // 1.5.1 Add timestampOffset to the presentation timestamp.
+            presentationTimestamp += m_timestampOffset;
+
+            // 1.5.2 Add timestampOffset to the decode timestamp.
+            decodeTimestamp += m_timestampOffset;
+
+            // 1.5.3 If the presentation timestamp or decode timestamp is less than the presentation start
+            // time, then run the end of stream algorithm with the error parameter set to "decode", and
+            // abort these steps.
+            MediaTime presentationStartTime = MediaTime::zeroTime();
+            if (presentationTimestamp < presentationStartTime || decodeTimestamp < presentationStartTime) {
+                m_source->endOfStream(decodeError(), IgnorableExceptionCode());
+                return;
+            }
+        }
+
+        // 1.6 Let track buffer equal the track buffer that the coded frame will be added to.
+        AtomicString trackID = sample->trackID();
+        auto it = m_trackBufferMap.find(trackID);
+        if (it == m_trackBufferMap.end())
+            it = m_trackBufferMap.add(trackID, TrackBuffer()).iterator;
+        TrackBuffer& trackBuffer = it->value;
+
+        // 1.7 If last decode timestamp for track buffer is set and decode timestamp is less than last
+        // decode timestamp:
+        // OR
+        // If last decode timestamp for track buffer is set and the difference between decode timestamp and
+        // last decode timestamp is greater than 2 times last frame duration:
+        if (trackBuffer.lastDecodeTimestamp.isValid() && (decodeTimestamp < trackBuffer.lastDecodeTimestamp
+            || abs(decodeTimestamp - trackBuffer.lastDecodeTimestamp) > (trackBuffer.lastFrameDuration * 2))) {
+            // 1.7.1 If mode equals "segments":
+            // Set highest presentation end timestamp to presentation timestamp.
+            m_highestPresentationEndTimestamp = presentationTimestamp;
+
+            // If mode equals "sequence":
+            // Set group start timestamp equal to the highest presentation end timestamp.
+            // FIXME: Add support for "sequence" mode.
+
+            for (auto i = m_trackBufferMap.values().begin(); i != m_trackBufferMap.values().end(); ++i) {
+                // 1.7.2 Unset the last decode timestamp on all track buffers.
+                i->lastDecodeTimestamp = MediaTime::invalidTime();
+                // 1.7.3 Unset the last frame duration on all track buffers.
+                i->lastFrameDuration = MediaTime::invalidTime();
+                // 1.7.4 Unset the highest presentation timestamp on all track buffers.
+                i->highestPresentationTimestamp = MediaTime::invalidTime();
+                // 1.7.5 Set the need random access point flag on all track buffers to true.
+                i->needRandomAccessFlag = true;
+            }
+
+            // 1.7.6 Jump to the Loop Top step above to restart processing of the current coded frame.
+            continue;
+        }
+
+        // 1.8 Let frame end timestamp equal the sum of presentation timestamp and frame duration.
+        MediaTime frameEndTimestamp = presentationTimestamp + frameDuration;
+
+        // 1.9 If presentation timestamp is less than appendWindowStart, then set the need random access
+        // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
+        // the next coded frame.
+        // 1.10 If frame end timestamp is greater than appendWindowEnd, then set the need random access
+        // point flag to true, drop the coded frame, and jump to the top of the loop to start processing
+        // the next coded frame.
+        // FIXME: implement append windows
+
+        // 1.11 If the need random access point flag on track buffer equals true, then run the following steps:
+        // 1.11.1 If the coded frame is not a random access point, then drop the coded frame and jump
+        // to the top of the loop to start processing the next coded frame.
+        // 1.11.2 Set the need random access point flag on track buffer to false.
+        // NOTE: MockSampleBoxes are not decodable.
+
+        // 1.12 Let spliced audio frame be an unset variable for holding audio splice information
+        // 1.13 Let spliced timed text frame be an unset variable for holding timed text splice information
+        // FIXME: Add support for sample splicing.
+
+        TrackBuffer::SampleMap erasedSamples;
+        MediaTime microsecond(1, 1000000);
+
+        // 1.14 If last decode timestamp for track buffer is unset and there is a coded frame in
+        // track buffer with a presentation timestamp less than or equal to presentation timestamp
+        // and presentation timestamp is less than this coded frame's presentation timestamp plus
+        // its frame duration, then run the following steps:
+        if (trackBuffer.lastDecodeTimestamp.isInvalid()) {
+            SampleContainsMediaTimeComparator comparator;
+            auto iter = std::lower_bound(trackBuffer.samples.begin(), trackBuffer.samples.end(), presentationTimestamp, comparator);
+            if (iter != trackBuffer.samples.end() && comparator.contains(iter->second.get(), presentationTimestamp)) {
+                // 1.14.1 Let overlapped frame be the coded frame in track buffer that matches the condition above.
+                RefPtr<MediaSample> overlappedFrame = iter->second;
+
+                // 1.14.2 If track buffer contains audio coded frames:
+                // Run the audio splice frame algorithm and if a splice frame is returned, assign it to
+                // spliced audio frame.
+                // FIXME: Add support for sample splicing.
+
+                // If track buffer contains video coded frames:
+                if (trackBuffer.description->isVideo()) {
+                    // 1.14.2.1 Let overlapped frame presentation timestamp equal the presentation timestamp
+                    // of overlapped frame.
+                    MediaTime overlappedFramePresentationTimestamp = overlappedFrame->presentationTime();
+
+                    // 1.14.2.2 Let remove window timestamp equal overlapped frame presentation timestamp
+                    // plus 1 microsecond.
+                    MediaTime removeWindowTimestamp = overlappedFramePresentationTimestamp + microsecond;
+
+                    // 1.14.2.3 If the presentation timestamp is less than the remove window timestamp,
+                    // then remove overlapped frame and any coded frames that depend on it from track buffer.
+                    if (presentationTimestamp < removeWindowTimestamp) {
+                        // NOTE: MockSampleBoxes don't have dependencies
+                        erasedSamples.insert(*iter);
+                        trackBuffer.samples.erase(iter);
+                    }
+                }
+
+                // If track buffer contains timed text coded frames:
+                // Run the text splice frame algorithm and if a splice frame is returned, assign it to spliced timed text frame.
+                // FIXME: Add support for sample splicing.
+            }
+        }
+
+        // 1.15 Remove existing coded frames in track buffer:
+        // If highest presentation timestamp for track buffer is not set:
+        if (trackBuffer.highestPresentationTimestamp.isInvalid()) {
+            // Remove all coded frames from track buffer that have a presentation timestamp greater than or
+            // equal to presentation timestamp and less than frame end timestamp.
+            SamplePresentationTimeIsWithinRangeComparator comparator;
+            std::pair<MediaTime, MediaTime> range(presentationTimestamp, frameEndTimestamp);
+            auto iter_pair = std::equal_range(trackBuffer.samples.begin(), trackBuffer.samples.end(), range, comparator);
+            if (iter_pair.first != trackBuffer.samples.end()) {
+                erasedSamples.insert(iter_pair.first, iter_pair.second);
+                trackBuffer.samples.erase(iter_pair.first, iter_pair.second);
+            }
+        }
+
+        // If highest presentation timestamp for track buffer is set and less than presentation timestamp
+        if (trackBuffer.highestPresentationTimestamp.isValid() && trackBuffer.highestPresentationTimestamp < presentationTimestamp) {
+            // Remove all coded frames from track buffer that have a presentation timestamp greater than highest
+            // presentation timestamp and less than or equal to frame end timestamp.
+            SamplePresentationTimeIsWithinRangeComparator comparator;
+            std::pair<MediaTime, MediaTime> range(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
+            auto iter_pair = std::equal_range(trackBuffer.samples.begin(), trackBuffer.samples.end(), range, comparator);
+            if (iter_pair.first != trackBuffer.samples.end()) {
+                erasedSamples.insert(iter_pair.first, iter_pair.second);
+                trackBuffer.samples.erase(iter_pair.first, iter_pair.second);
+            }
+        }
+
+        // 1.16 Remove decoding dependencies of the coded frames removed in the previous step:
+        if (!erasedSamples.empty()) {
+            // If detailed information about decoding dependencies is available:
+            // FIXME: Add support for detailed dependency information
+
+            // Otherwise: Remove all coded frames between the coded frames removed in the previous step
+            // and the next random access point after those removed frames.
+            auto first_iter = std::upper_bound(trackBuffer.samples.begin(), trackBuffer.samples.end(), *erasedSamples.begin(), SampleLessThanComparator());
+            auto second_iter = std::find_if(first_iter, trackBuffer.samples.end(), SampleIsRandomAccessPredicate());
+            if (first_iter != trackBuffer.samples.end()) {
+                trackBuffer.samples.erase(first_iter, second_iter);
+                erasedSamples.insert(first_iter, second_iter);
+            }
+        }
+
+        // 1.17 If spliced audio frame is set:
+        // Add spliced audio frame to the track buffer.
+        // If spliced timed text frame is set:
+        // Add spliced timed text frame to the track buffer.
+        // FIXME: Add support for sample splicing.
+
+        // Otherwise:
+        // Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
+        trackBuffer.samples.insert(TrackBuffer::SampleMap::value_type(presentationTimestamp, sample));
+        trackBuffer.decodeQueue.insert(TrackBuffer::SampleMap::value_type(decodeTimestamp, sample));
+
+        // 1.18 Set last decode timestamp for track buffer to decode timestamp.
+        trackBuffer.lastDecodeTimestamp = decodeTimestamp;
+
+        // 1.19 Set last frame duration for track buffer to frame duration.
+        trackBuffer.lastFrameDuration = frameDuration;
+
+        // 1.20 If highest presentation timestamp for track buffer is unset or frame end timestamp is greater
+        // than highest presentation timestamp, then set highest presentation timestamp for track buffer
+        // to frame end timestamp.
+        if (trackBuffer.highestPresentationTimestamp.isInvalid() || frameEndTimestamp > trackBuffer.highestPresentationTimestamp)
+            trackBuffer.highestPresentationTimestamp = frameEndTimestamp;
+
+        if (erasedSamples.size()) {
+            RefPtr<TimeRanges> erasedRanges = TimeRanges::create();
+            for (auto iter = erasedSamples.begin(); iter != erasedSamples.end(); ++iter) {
+                double start = iter->first.toDouble();
+                double end = ((iter->first + iter->second->duration()) + microsecond).toDouble();
+                erasedRanges->add(start, end);
+            }
+            erasedRanges->invert();
+            m_buffered->intersectWith(erasedRanges.get());
+        }
+
+        m_buffered->add(presentationTimestamp.toDouble(), (presentationTimestamp + frameDuration + microsecond).toDouble());
+
+        break;
+    } while (1);
 }
 
 bool SourceBuffer::sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const
 {
-    return false;
+    return m_audioTracks->length();
 }
 
 bool SourceBuffer::sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const
 {
-    return false;
+    return m_videoTracks->length();
+}
+
+void SourceBuffer::videoTrackSelectedChanged(VideoTrack* track)
+{
+    // 2.4.5 Changes to selected/enabled track state
+    // If the selected video track changes, then run the following steps:
+    // 1. If the SourceBuffer associated with the previously selected video track is not associated with
+    // any other enabled tracks, run the following steps:
+    if (track->selected()
+        && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
+        && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
+        && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
+        // 1.1 Remove the SourceBuffer from activeSourceBuffers.
+        // 1.2 Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
+        setActive(false);
+    } else if (!track->selected()) {
+        // 2. If the SourceBuffer associated with the newly selected video track is not already in activeSourceBuffers,
+        // run the following steps:
+        // 2.1 Add the SourceBuffer to activeSourceBuffers.
+        // 2.2 Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
+        setActive(true);
+    }
+
+    if (!isRemoved())
+        m_source->mediaElement()->videoTrackSelectedChanged(track);
+}
+
+void SourceBuffer::audioTrackEnabledChanged(AudioTrack* track)
+{
+    // 2.4.5 Changes to selected/enabled track state
+    // If an audio track becomes disabled and the SourceBuffer associated with this track is not
+    // associated with any other enabled or selected track, then run the following steps:
+    if (track->enabled()
+        && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
+        && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
+        && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
+        // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
+        // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
+        setActive(false);
+    } else if (!track->enabled()) {
+        // If an audio track becomes enabled and the SourceBuffer associated with this track is
+        // not already in activeSourceBuffers, then run the following steps:
+        // 1. Add the SourceBuffer associated with the audio track to activeSourceBuffers
+        // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
+        setActive(true);
+    }
+
+    if (!isRemoved())
+        m_source->mediaElement()->audioTrackEnabledChanged(track);
+}
+
+void SourceBuffer::textTrackModeChanged(TextTrack* track)
+{
+    // 2.4.5 Changes to selected/enabled track state
+    // If a text track mode becomes "disabled" and the SourceBuffer associated with this track is not
+    // associated with any other enabled or selected track, then run the following steps:
+    if (track->mode() == TextTrack::disabledKeyword()
+        && (!m_videoTracks || !m_videoTracks->isAnyTrackEnabled())
+        && (!m_audioTracks || !m_audioTracks->isAnyTrackEnabled())
+        && (!m_textTracks || !m_textTracks->isAnyTrackEnabled())) {
+        // 1. Remove the SourceBuffer associated with the audio track from activeSourceBuffers
+        // 2. Queue a task to fire a simple event named removesourcebuffer at activeSourceBuffers
+        setActive(false);
+    } else {
+        // If a text track mode becomes "showing" or "hidden" and the SourceBuffer associated with this
+        // track is not already in activeSourceBuffers, then run the following steps:
+        // 1. Add the SourceBuffer associated with the text track to activeSourceBuffers
+        // 2. Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
+        setActive(true);
+    }
+
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackModeChanged(track);
+}
+
+void SourceBuffer::textTrackAddCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
+{
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackAddCue(track, cue);
+}
+
+void SourceBuffer::textTrackAddCues(TextTrack* track, TextTrackCueList const* cueList)
+{
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackAddCues(track, cueList);
+}
+
+void SourceBuffer::textTrackRemoveCue(TextTrack* track, WTF::PassRefPtr<TextTrackCue> cue)
+{
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackRemoveCue(track, cue);
+}
+
+void SourceBuffer::textTrackRemoveCues(TextTrack* track, TextTrackCueList const* cueList)
+{
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackRemoveCues(track, cueList);
+}
+
+void SourceBuffer::textTrackKindChanged(TextTrack* track)
+{
+    if (!isRemoved())
+        m_source->mediaElement()->textTrackKindChanged(track);
 }
 
 } // namespace WebCore
index 0e605cf..3baba85 100644 (file)
 #if ENABLE(MEDIA_SOURCE)
 
 #include "ActiveDOMObject.h"
+#include "AudioTrack.h"
 #include "EventTarget.h"
 #include "ExceptionCode.h"
 #include "GenericEventQueue.h"
 #include "ScriptWrappable.h"
 #include "SourceBufferPrivateClient.h"
+#include "TextTrack.h"
 #include "Timer.h"
+#include "VideoTrack.h"
 #include <runtime/ArrayBufferView.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
+
+class AudioTrackList;
 class MediaSource;
 class SourceBufferPrivate;
+class TextTrackList;
 class TimeRanges;
+class VideoTrackList;
 
-class SourceBuffer FINAL : public RefCounted<SourceBuffer>, public ActiveDOMObject, public EventTargetWithInlineData, public ScriptWrappable, public SourceBufferPrivateClient {
+class SourceBuffer FINAL : public RefCounted<SourceBuffer>, public ActiveDOMObject, public EventTargetWithInlineData, public ScriptWrappable, public SourceBufferPrivateClient, public AudioTrackClient, public VideoTrackClient, public TextTrackClient {
 public:
     static PassRef<SourceBuffer> create(PassRef<SourceBufferPrivate>, MediaSource*);
 
@@ -59,6 +66,7 @@ public:
     // SourceBuffer.idl methods
     bool updating() const { return m_updating; }
     PassRefPtr<TimeRanges> buffered(ExceptionCode&) const;
+    const RefPtr<TimeRanges>& buffered() const;
     double timestampOffset() const;
     void setTimestampOffset(double, ExceptionCode&);
     void appendBuffer(PassRefPtr<ArrayBuffer> data, ExceptionCode&);
@@ -68,6 +76,12 @@ public:
     void abortIfUpdating();
     void removedFromMediaSource();
 
+#if ENABLE(VIDEO_TRACK)
+    VideoTrackList* videoTracks();
+    AudioTrackList* audioTracks();
+    TextTrackList* textTracks();
+#endif
+
     // ActiveDOMObject interface
     virtual bool hasPendingActivity() const OVERRIDE;
     virtual void stop() OVERRIDE;
@@ -88,27 +102,68 @@ private:
     SourceBuffer(PassRef<SourceBufferPrivate>, MediaSource*);
 
     // SourceBufferPrivateClient
-    virtual void sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const WTF::AtomicString&);
+    virtual void sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const WTF::AtomicString&) OVERRIDE;
     virtual void sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment&) OVERRIDE;
     virtual void sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample>) OVERRIDE;
     virtual bool sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const OVERRIDE;
     virtual bool sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const OVERRIDE;
 
+    // AudioTrackClient
+    virtual void audioTrackEnabledChanged(AudioTrack*) OVERRIDE;
+
+    // VideoTrackClient
+    virtual void videoTrackSelectedChanged(VideoTrack*) OVERRIDE;
+
+    // TextTrackClient
+    virtual void textTrackKindChanged(TextTrack*) OVERRIDE;
+    virtual void textTrackModeChanged(TextTrack*) OVERRIDE;
+    virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*) OVERRIDE;
+    virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*) OVERRIDE;
+    virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>) OVERRIDE;
+    virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>) OVERRIDE;
+
+    static const WTF::AtomicString& decodeError();
+    static const WTF::AtomicString& networkError();
+
     bool isRemoved() const;
     void scheduleEvent(const AtomicString& eventName);
 
     void appendBufferInternal(unsigned char*, unsigned, ExceptionCode&);
     void appendBufferTimerFired(Timer<SourceBuffer>*);
 
+    void setActive(bool);
+
+    bool validateInitializationSegment(const InitializationSegment&);
+
     RefPtr<SourceBufferPrivate> m_private;
     MediaSource* m_source;
     GenericEventQueue m_asyncEventQueue;
 
     bool m_updating;
-    double m_timestampOffset;
 
     Vector<unsigned char> m_pendingAppendData;
     Timer<SourceBuffer> m_appendBufferTimer;
+
+    RefPtr<VideoTrackList> m_videoTracks;
+    RefPtr<AudioTrackList> m_audioTracks;
+    RefPtr<TextTrackList> m_textTracks;
+
+    Vector<AtomicString> m_videoCodecs;
+    Vector<AtomicString> m_audioCodecs;
+    Vector<AtomicString> m_textCodecs;
+
+    MediaTime m_timestampOffset;
+    MediaTime m_highestPresentationEndTimestamp;
+
+    struct TrackBuffer;
+    HashMap<AtomicString, TrackBuffer> m_trackBufferMap;
+    bool m_receivedFirstInitializationSegment;
+    RefPtr<TimeRanges> m_buffered;
+    bool m_active;
+
+    enum AppendStateType { WaitingForSegment, ParsingInitSegment, ParsingMediaSegment };
+    AppendStateType m_appendState;
+
 };
 
 } // namespace WebCore
index abdf3b6..f57a707 100644 (file)
 
     // Abort the current segment append sequence.
     [RaisesException] void abort();
+    
+    // Track support
+    [Conditional=VIDEO_TRACK] readonly attribute AudioTrackList audioTracks;
+    [Conditional=VIDEO_TRACK] readonly attribute VideoTrackList videoTracks;
+    [Conditional=VIDEO_TRACK] readonly attribute TextTrackList textTracks;
 };
 
index 944ad7e..37f6efa 100644 (file)
@@ -59,6 +59,9 @@ public:
     bool contains(SourceBuffer* buffer) { return m_list.find(buffer) != notFound; }
     void clear();
 
+    Vector<RefPtr<SourceBuffer>>::iterator begin() { return m_list.begin(); }
+    Vector<RefPtr<SourceBuffer>>::iterator end() { return m_list.end(); }
+
     // EventTarget interface
     virtual EventTargetInterface eventTargetInterface() const OVERRIDE { return SourceBufferListEventTargetInterfaceType; }
     virtual ScriptExecutionContext* scriptExecutionContext() const OVERRIDE { return m_scriptExecutionContext; }
diff --git a/Source/WebCore/Modules/mediasource/TextTrackMediaSource.h b/Source/WebCore/Modules/mediasource/TextTrackMediaSource.h
new file mode 100644 (file)
index 0000000..8efd4e8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef TextTrackMediaSource_h
+#define TextTrackMediaSource_h
+
+#if ENABLE(MEDIA_SOURCE) && ENABLE(VIDEO_TRACK)
+
+#include "TextTrack.h"
+
+namespace WebCore {
+
+class SourceBuffer;
+
+class TextTrackMediaSource {
+public:
+    static SourceBuffer* sourceBuffer(TextTrack* track) { return track->sourceBuffer(); }
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebCore/Modules/mediasource/TextTrackMediaSource.idl b/Source/WebCore/Modules/mediasource/TextTrackMediaSource.idl
new file mode 100644 (file)
index 0000000..567dd35
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+[
+    Conditional=MEDIA_SOURCE&VIDEO_TRACK,
+]
+partial interface TextTrack {
+    readonly attribute SourceBuffer sourceBuffer;
+};
diff --git a/Source/WebCore/Modules/mediasource/VideoTrackMediaSource.h b/Source/WebCore/Modules/mediasource/VideoTrackMediaSource.h
new file mode 100644 (file)
index 0000000..f195709
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef VideoTrackMediaSource_h
+#define VideoTrackMediaSource_h
+
+#if ENABLE(MEDIA_SOURCE) && ENABLE(VIDEO_TRACK)
+
+#include "VideoTrack.h"
+
+namespace WebCore {
+
+class SourceBuffer;
+
+class VideoTrackMediaSource {
+public:
+    static SourceBuffer* sourceBuffer(VideoTrack* track) { return track->sourceBuffer(); }
+};
+
+}
+
+#endif
+
+#endif
diff --git a/Source/WebCore/Modules/mediasource/VideoTrackMediaSource.idl b/Source/WebCore/Modules/mediasource/VideoTrackMediaSource.idl
new file mode 100644 (file)
index 0000000..4866a28
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+[
+    Conditional=MEDIA_SOURCE&VIDEO_TRACK,
+]
+partial interface VideoTrack {
+    readonly attribute SourceBuffer sourceBuffer;
+};
index 8b795e1..a503fc1 100644 (file)
                CD54DE4B17469C6D005E5B36 /* AudioSessionMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */; };
                CD61FE671794AADB004101EB /* MediaSourceRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1A942E115B5CE2200D525D1 /* MediaSourceRegistry.cpp */; };
                CD61FE681794AADB004101EB /* MediaSourceRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = B1A942E215B5CE2200D525D1 /* MediaSourceRegistry.h */; };
+
+               CD641EB31818F5ED00EE4C41 /* MediaSourcePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = CD641EB11818F5ED00EE4C41 /* MediaSourcePrivate.h */; };
+               CD641EB41818F5ED00EE4C41 /* SourceBufferPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = CD641EB21818F5ED00EE4C41 /* SourceBufferPrivate.h */; };
                CD641EBF1819B36000EE4C41 /* MediaTimeMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD641EBD1819B35900EE4C41 /* MediaTimeMac.cpp */; };
                CD641EC01819B36000EE4C41 /* MediaTimeMac.h in Headers */ = {isa = PBXBuildFile; fileRef = CD641EBE1819B35900EE4C41 /* MediaTimeMac.h */; };
                CD7E05221651C28200C1201F /* WebCoreAVFResourceLoader.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD7E05211651A84100C1201F /* WebCoreAVFResourceLoader.mm */; };
                CD82030D1395AB6A00F956C6 /* WebVideoFullscreenHUDWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD8203091395AB6A00F956C6 /* WebVideoFullscreenHUDWindowController.mm */; };
                CD8203101395ACE700F956C6 /* WebWindowAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = CD82030E1395ACE700F956C6 /* WebWindowAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                CD8203111395ACE700F956C6 /* WebWindowAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD82030F1395ACE700F956C6 /* WebWindowAnimation.mm */; };
+               CD8B5A46180DFF4E008B8E65 /* VideoTrackMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CD8B5A45180DFF4E008B8E65 /* VideoTrackMediaSource.h */; };
+               CD8B5A49180E138B008B8E65 /* TextTrackMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CD8B5A48180E138B008B8E65 /* TextTrackMediaSource.h */; };
+               CD8B5A4C180E17C0008B8E65 /* AudioTrackMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CD8B5A4B180E17C0008B8E65 /* AudioTrackMediaSource.h */; };
                CD9DE17417AAC74C00EA386D /* JSMediaSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD9DE17217AAC74C00EA386D /* JSMediaSource.cpp */; };
                CD9DE17517AAC74C00EA386D /* JSMediaSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CD9DE17317AAC74C00EA386D /* JSMediaSource.h */; };
                CD9DE17A17AAC75B00EA386D /* JSSourceBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD9DE17617AAC75B00EA386D /* JSSourceBuffer.cpp */; };
                CDEA7C851276230400B846DD /* RenderFullScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDEA7C831276230400B846DD /* RenderFullScreen.cpp */; };
                CDEE393717974259001D7580 /* PublicURLManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDEE393617974259001D7580 /* PublicURLManager.cpp */; };
                CDEF4FD717E85C8F00AEE24B /* GridLength.h in Headers */ = {isa = PBXBuildFile; fileRef = CDEF4FD617E85C8F00AEE24B /* GridLength.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               CDF2B004181F059C00F2B424 /* MediaDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = CDF2B003181F059C00F2B424 /* MediaDescription.h */; };
                CDF65CC8145B1E7500C4C7AA /* MediaController.h in Headers */ = {isa = PBXBuildFile; fileRef = CD27F6E4145767870078207D /* MediaController.h */; settings = {ATTRIBUTES = (Private, ); }; };
                CDF65CCA145B448800C4C7AA /* MediaControllerInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = CDF65CC9145B43A700C4C7AA /* MediaControllerInterface.h */; settings = {ATTRIBUTES = (Private, ); }; };
                CE057FA51220731100A476D5 /* DocumentMarkerController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE057FA31220731100A476D5 /* DocumentMarkerController.cpp */; };
                07C59B5A17F4B208000FBCBB /* JSAudioStreamTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAudioStreamTrack.h; sourceTree = "<group>"; };
                07C59B5B17F4B208000FBCBB /* JSVideoStreamTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSVideoStreamTrack.cpp; sourceTree = "<group>"; };
                07C59B5C17F4B208000FBCBB /* JSVideoStreamTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVideoStreamTrack.h; sourceTree = "<group>"; };
-               07C59B6117F4CF87000FBCBB /* MockMediaStreamCenter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MockMediaStreamCenter.cpp; path = mock/MockMediaStreamCenter.cpp; sourceTree = "<group>"; };
-               07C59B6217F4CF87000FBCBB /* MockMediaStreamCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockMediaStreamCenter.h; path = mock/MockMediaStreamCenter.h; sourceTree = "<group>"; };
+               07C59B6117F4CF87000FBCBB /* MockMediaStreamCenter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockMediaStreamCenter.cpp; sourceTree = "<group>"; };
+               07C59B6217F4CF87000FBCBB /* MockMediaStreamCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockMediaStreamCenter.h; sourceTree = "<group>"; };
                07C59B6517F784BA000FBCBB /* MediaSourceStates.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaSourceStates.cpp; sourceTree = "<group>"; };
                07C59B6617F784BA000FBCBB /* MediaSourceStates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSourceStates.h; sourceTree = "<group>"; };
                07C59B6717F784BA000FBCBB /* MediaSourceStates.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = MediaSourceStates.idl; sourceTree = "<group>"; };
                0FD308D4117D168400A791F7 /* RenderIFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderIFrame.h; sourceTree = "<group>"; };
                0FD723800EC8BD9300CA5DD7 /* FloatQuad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatQuad.h; sourceTree = "<group>"; };
                0FD723810EC8BD9300CA5DD7 /* FloatQuad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FloatQuad.cpp; sourceTree = "<group>"; };
-               0FE71403142170B800DB33BA /* ScrollbarThemeMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScrollbarThemeMock.cpp; path = mock/ScrollbarThemeMock.cpp; sourceTree = "<group>"; };
-               0FE71404142170B800DB33BA /* ScrollbarThemeMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScrollbarThemeMock.h; path = mock/ScrollbarThemeMock.h; sourceTree = "<group>"; };
+               0FE71403142170B800DB33BA /* ScrollbarThemeMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollbarThemeMock.cpp; sourceTree = "<group>"; };
+               0FE71404142170B800DB33BA /* ScrollbarThemeMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollbarThemeMock.h; sourceTree = "<group>"; };
                0FE71415142189FC00DB33BA /* ScrollbarTheme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollbarTheme.cpp; sourceTree = "<group>"; };
                0FF50259102BA9010066F39A /* DOMStyleMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMStyleMedia.h; sourceTree = "<group>"; };
                0FF5025A102BA9010066F39A /* DOMStyleMedia.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMStyleMedia.mm; sourceTree = "<group>"; };
                59102FBA14327D3B003C9D04 /* ContentSearchUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentSearchUtils.h; sourceTree = "<group>"; };
                5913A23F13D49EBA00F5B05C /* IdentifiersFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifiersFactory.cpp; sourceTree = "<group>"; };
                5913A24013D49EBA00F5B05C /* IdentifiersFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdentifiersFactory.h; sourceTree = "<group>"; };
-               59309A1011F4AE5800250603 /* DeviceOrientationClientMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeviceOrientationClientMock.cpp; path = mock/DeviceOrientationClientMock.cpp; sourceTree = "<group>"; };
-               59309A1211F4AE6A00250603 /* DeviceOrientationClientMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeviceOrientationClientMock.h; path = mock/DeviceOrientationClientMock.h; sourceTree = "<group>"; };
+               59309A1011F4AE5800250603 /* DeviceOrientationClientMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceOrientationClientMock.cpp; sourceTree = "<group>"; };
+               59309A1211F4AE6A00250603 /* DeviceOrientationClientMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceOrientationClientMock.h; sourceTree = "<group>"; };
                5958F1CB1343917C0080B31F /* XMLViewer.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = XMLViewer.css; sourceTree = "<group>"; };
                5958F1CC1343917C0080B31F /* XMLViewer.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = XMLViewer.js; sourceTree = "<group>"; };
                598365DC1355F53C001B185D /* JSPositionCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPositionCallback.h; sourceTree = "<group>"; };
                AAD766E8157E502F00E85423 /* InspectorCanvasAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorCanvasAgent.cpp; sourceTree = "<group>"; };
                AAD766E9157E502F00E85423 /* InspectorCanvasAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorCanvasAgent.h; sourceTree = "<group>"; };
                AAD766EA157E502F00E85423 /* InspectorCanvasInstrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorCanvasInstrumentation.h; sourceTree = "<group>"; };
-               AAE27B7416CBFC0D00623043 /* PlatformSpeechSynthesizerMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformSpeechSynthesizerMock.cpp; path = mock/PlatformSpeechSynthesizerMock.cpp; sourceTree = "<group>"; };
-               AAE27B7516CBFC0D00623043 /* PlatformSpeechSynthesizerMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformSpeechSynthesizerMock.h; path = mock/PlatformSpeechSynthesizerMock.h; sourceTree = "<group>"; };
+               AAE27B7416CBFC0D00623043 /* PlatformSpeechSynthesizerMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformSpeechSynthesizerMock.cpp; sourceTree = "<group>"; };
+               AAE27B7516CBFC0D00623043 /* PlatformSpeechSynthesizerMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformSpeechSynthesizerMock.h; sourceTree = "<group>"; };
                AAF5B7B11524B4BD0004CB49 /* WebSocketFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketFrame.cpp; sourceTree = "<group>"; };
                AB23A32509BBA7D00067CC53 /* BeforeTextInsertedEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BeforeTextInsertedEvent.cpp; sourceTree = "<group>"; };
                AB23A32609BBA7D00067CC53 /* BeforeTextInsertedEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BeforeTextInsertedEvent.h; sourceTree = "<group>"; };
                CD54A75E180F535000B076C9 /* MediaSourcePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSourcePrivate.h; sourceTree = "<group>"; };
                CD54DE4517468B6F005E5B36 /* AudioSessionManagerMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSessionManagerMac.cpp; sourceTree = "<group>"; };
                CD54DE4917469C6D005E5B36 /* AudioSessionMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSessionMac.cpp; sourceTree = "<group>"; };
+               CD641EB11818F5ED00EE4C41 /* MediaSourcePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSourcePrivate.h; sourceTree = "<group>"; };
+               CD641EB21818F5ED00EE4C41 /* SourceBufferPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceBufferPrivate.h; sourceTree = "<group>"; };
                CD641EBD1819B35900EE4C41 /* MediaTimeMac.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MediaTimeMac.cpp; sourceTree = "<group>"; };
                CD641EBE1819B35900EE4C41 /* MediaTimeMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaTimeMac.h; sourceTree = "<group>"; };
+               CD641EC7181ED60100EE4C41 /* MediaSample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaSample.h; sourceTree = "<group>"; };
                CD7E05201651A84100C1201F /* WebCoreAVFResourceLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WebCoreAVFResourceLoader.h; path = objc/WebCoreAVFResourceLoader.h; sourceTree = "<group>"; };
                CD7E05211651A84100C1201F /* WebCoreAVFResourceLoader.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WebCoreAVFResourceLoader.mm; path = objc/WebCoreAVFResourceLoader.mm; sourceTree = "<group>"; };
                CD8203061395AB6A00F956C6 /* WebVideoFullscreenController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVideoFullscreenController.h; sourceTree = "<group>"; };
                CD8203091395AB6A00F956C6 /* WebVideoFullscreenHUDWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebVideoFullscreenHUDWindowController.mm; sourceTree = "<group>"; };
                CD82030E1395ACE700F956C6 /* WebWindowAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebWindowAnimation.h; sourceTree = "<group>"; };
                CD82030F1395ACE700F956C6 /* WebWindowAnimation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebWindowAnimation.mm; sourceTree = "<group>"; };
+               CD8B5A44180DD8D6008B8E65 /* VideoTrackMediaSource.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = VideoTrackMediaSource.idl; sourceTree = "<group>"; };
+               CD8B5A45180DFF4E008B8E65 /* VideoTrackMediaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoTrackMediaSource.h; sourceTree = "<group>"; };
+               CD8B5A47180E1361008B8E65 /* TextTrackMediaSource.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextTrackMediaSource.idl; sourceTree = "<group>"; };
+               CD8B5A48180E138B008B8E65 /* TextTrackMediaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTrackMediaSource.h; sourceTree = "<group>"; };
+               CD8B5A4A180E17A3008B8E65 /* AudioTrackMediaSource.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AudioTrackMediaSource.idl; sourceTree = "<group>"; };
+               CD8B5A4B180E17C0008B8E65 /* AudioTrackMediaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioTrackMediaSource.h; sourceTree = "<group>"; };
                CD9DE17217AAC74C00EA386D /* JSMediaSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaSource.cpp; sourceTree = "<group>"; };
                CD9DE17317AAC74C00EA386D /* JSMediaSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMediaSource.h; sourceTree = "<group>"; };
                CD9DE17617AAC75B00EA386D /* JSSourceBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSourceBuffer.cpp; sourceTree = "<group>"; };
                CDEE393617974259001D7580 /* PublicURLManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PublicURLManager.cpp; sourceTree = "<group>"; };
                CDEE393817974274001D7580 /* URLRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = URLRegistry.h; sourceTree = "<group>"; };
                CDEF4FD617E85C8F00AEE24B /* GridLength.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GridLength.h; path = style/GridLength.h; sourceTree = "<group>"; };
+               CDF2B003181F059C00F2B424 /* MediaDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaDescription.h; sourceTree = "<group>"; };
                CDF65CC9145B43A700C4C7AA /* MediaControllerInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaControllerInterface.h; sourceTree = "<group>"; };
                CDF65CCC145B6AFE00C4C7AA /* JSHTMLMediaElementCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLMediaElementCustom.cpp; sourceTree = "<group>"; };
                CE057FA31220731100A476D5 /* DocumentMarkerController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentMarkerController.cpp; sourceTree = "<group>"; };
                                0FE71403142170B800DB33BA /* ScrollbarThemeMock.cpp */,
                                0FE71404142170B800DB33BA /* ScrollbarThemeMock.h */,
                        );
-                       name = mock;
+                       path = mock;
                        sourceTree = "<group>";
                };
                5DA5E0F9102B950400088CF9 /* WebSockets */ = {
                B1A942DD15B5CE2200D525D1 /* mediasource */ = {
                        isa = PBXGroup;
                        children = (
+                               CD8B5A4B180E17C0008B8E65 /* AudioTrackMediaSource.h */,
+                               CD8B5A4A180E17A3008B8E65 /* AudioTrackMediaSource.idl */,
                                CD9DE17E17AAD64E00EA386D /* DOMURLMediaSource.cpp */,
                                CD9DE17F17AAD64E00EA386D /* DOMURLMediaSource.h */,
                                CD9DE18017AAD64E00EA386D /* DOMURLMediaSource.idl */,
                                CD3A495B17A9D01B00274E42 /* SourceBufferList.cpp */,
                                CD3A495C17A9D01B00274E42 /* SourceBufferList.h */,
                                CD3A495D17A9D01B00274E42 /* SourceBufferList.idl */,
+                               CD8B5A48180E138B008B8E65 /* TextTrackMediaSource.h */,
+                               CD8B5A47180E1361008B8E65 /* TextTrackMediaSource.idl */,
+                               CD8B5A45180DFF4E008B8E65 /* VideoTrackMediaSource.h */,
+                               CD8B5A44180DD8D6008B8E65 /* VideoTrackMediaSource.idl */,
                        );
                        path = mediasource;
                        sourceTree = "<group>";
                B2A015910AF6CD53006BCE0E /* graphics */ = {
                        isa = PBXGroup;
                        children = (
+                               CD641EB11818F5ED00EE4C41 /* MediaSourcePrivate.h */,
+                               CD641EB21818F5ED00EE4C41 /* SourceBufferPrivate.h */,
                                076F0D0812B8192700C26AA4 /* avfoundation */,
                                499B3EC0128CCC1800E726C2 /* ca */,
                                B27535290B053814002CE64F /* cg */,
                                A8239DFE09B3CF8A00B60641 /* Logging.cpp */,
                                A8239DFF09B3CF8A00B60641 /* Logging.h */,
                                E187056216E54A0D00585E97 /* MainThreadTask.h */,
+                               CDF2B003181F059C00F2B424 /* MediaDescription.h */,
+                               CD641EC7181ED60100EE4C41 /* MediaSample.h */,
                                657EDA061385CB97004E0645 /* MemoryPressureHandler.cpp */,
                                657EDA071385CB97004E0645 /* MemoryPressureHandler.h */,
                                BC772C4C0C4EB3040083285F /* MIMETypeRegistry.cpp */,
                                29A812430FBB9C1D00510293 /* AccessibilityListBox.h in Headers */,
                                29A812420FBB9C1D00510293 /* AccessibilityListBoxOption.h in Headers */,
                                07B0113F1032242200FBDC33 /* AccessibilityMediaControls.h in Headers */,
+                               CDF2B004181F059C00F2B424 /* MediaDescription.h in Headers */,
                                76CDD2F31103DA6600680521 /* AccessibilityMenuList.h in Headers */,
                                76CDD2F71103DA6600680521 /* AccessibilityMenuListOption.h in Headers */,
                                76CDD2F51103DA6600680521 /* AccessibilityMenuListPopup.h in Headers */,
                                FD3160BD12B0272A00C1A359 /* AudioDestinationMac.h in Headers */,
                                FD31600812B0267600C1A359 /* AudioDestinationNode.h in Headers */,
                                FD31608012B026F700C1A359 /* AudioDSPKernel.h in Headers */,
+                               CD641EB31818F5ED00EE4C41 /* MediaSourcePrivate.h in Headers */,
                                FD31608212B026F700C1A359 /* AudioDSPKernelProcessor.h in Headers */,
                                FD31608312B026F700C1A359 /* AudioFileReader.h in Headers */,
                                078E094C17D1709600420AA1 /* MediaStreamAudioDestinationNode.h in Headers */,
                                A871DE280A152AC800B12A68 /* HTMLFrameSetElement.h in Headers */,
                                A871DE2D0A152AC800B12A68 /* HTMLHeadElement.h in Headers */,
                                A8EA7CB80A192B9C00A8EF5F /* HTMLHeadingElement.h in Headers */,
+                               CD8B5A49180E138B008B8E65 /* TextTrackMediaSource.h in Headers */,
                                A8EA7CAF0A192B9C00A8EF5F /* HTMLHRElement.h in Headers */,
                                A871DE270A152AC800B12A68 /* HTMLHtmlElement.h in Headers */,
                                A89570A016E9BD5900184E55 /* HTMLIdentifier.h in Headers */,
                                B2FA3DDD0AB75A6F000E5AC4 /* JSSVGPathSegMovetoAbs.h in Headers */,
                                B2FA3DDF0AB75A6F000E5AC4 /* JSSVGPathSegMovetoRel.h in Headers */,
                                0705852117FDC140005F2BCB /* MediaTrackConstraint.h in Headers */,
+                               CD8B5A46180DFF4E008B8E65 /* VideoTrackMediaSource.h in Headers */,
                                B2FA3DE10AB75A6F000E5AC4 /* JSSVGPatternElement.h in Headers */,
                                8542A7950AE5C94100DF58DF /* JSSVGPoint.h in Headers */,
                                51D719CA181106E00016DC51 /* IDBDatabaseCallbacks.h in Headers */,
                                2917B5621473496C0052C9D0 /* LayerFlushScheduler.h in Headers */,
                                2917B5631473496C0052C9D0 /* LayerFlushSchedulerClient.h in Headers */,
                                93F72AF31666EDFC002A02BD /* LayerPool.h in Headers */,
+                               CD8B5A4C180E17C0008B8E65 /* AudioTrackMediaSource.h in Headers */,
                                141DC050164834B900371E5A /* LayoutBoxExtent.h in Headers */,
                                931D72F615FE695300C4C07E /* LayoutMilestones.h in Headers */,
                                141DC051164834B900371E5A /* LayoutPoint.h in Headers */,
                                FD00D7A514A3F61900734011 /* SincResampler.h in Headers */,
                                51327D6011A33A2B004F9D65 /* SinkDocument.h in Headers */,
                                49E911CD0EF86D47009D0CAF /* SkewTransformOperation.h in Headers */,
+                               CD641EB41818F5ED00EE4C41 /* SourceBufferPrivate.h in Headers */,
                                4150F9F112B6E0E70008C860 /* SliderThumbElement.h in Headers */,
                                4B6FA6F40C39E48C00087011 /* SmartReplace.h in Headers */,
                                E4AFD00C0DAF335400F5F55C /* SMILTime.h in Headers */,
index 2929807..ebbd46b 100644 (file)
@@ -47,6 +47,34 @@ void JSAudioTrack::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.addOpaqueRoot(root(&audioTrack));
 }
 
+void JSAudioTrack::setKind(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setKind(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
+void JSAudioTrack::setLanguage(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setLanguage(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
 } // namespace WebCore
 
 #endif
index 9846fb9..078f6f2 100644 (file)
@@ -48,6 +48,34 @@ void JSTextTrack::visitChildren(JSCell* cell, SlotVisitor& visitor)
     textTrack.visitJSEventListeners(visitor);
 }
 
+void JSTextTrack::setKind(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setKind(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
+void JSTextTrack::setLanguage(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setLanguage(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
 } // namespace WebCore
 
 #endif
index ec3adcc..a82e7b8 100644 (file)
@@ -47,6 +47,34 @@ void JSVideoTrack::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.addOpaqueRoot(root(&videoTrack));
 }
 
+void JSVideoTrack::setKind(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setKind(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
+void JSVideoTrack::setLanguage(ExecState* exec, JSValue value)
+{
+    UNUSED_PARAM(exec);
+#if ENABLE(MEDIA_SOURCE)
+    const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec));
+    if (exec->hadException())
+        return;
+    impl().setLanguage(nativeValue);
+#else
+    UNUSED_PARAM(value);
+    return;
+#endif
+}
+
 } // namespace WebCore
 
 #endif
index 4b0c5c7..1aebbde 100644 (file)
@@ -1115,7 +1115,7 @@ void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentT
         m_mediaSource = HTMLMediaSource::lookup(url.string());
 
     if (m_mediaSource) {
-        if (m_mediaSource->attachToElement())
+        if (m_mediaSource->attachToElement(this))
             m_player->load(url, contentType, m_mediaSource);
         else {
             // Forget our reference to the MediaSource, so we leave it alone
@@ -2893,6 +2893,7 @@ void HTMLMediaElement::mediaPlayerDidAddTextTrack(PassRefPtr<InbandTextTrackPriv
     // 4.8.10.12.2 Sourcing in-band text tracks
     // 1. Associate the relevant data with a new text track and its corresponding new TextTrack object.
     RefPtr<InbandTextTrack> textTrack = InbandTextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, prpTrack);
+    textTrack->setMediaElement(this);
     
     // 2. Set the new text track's kind, label, and language based on the semantics of the relevant data,
     // as defined by the relevant specification. If there is no label in that data, then the label must
index 198fdfe..b495c26 100644 (file)
@@ -36,6 +36,7 @@
 
 namespace WebCore {
 
+class HTMLMediaElement;
 class MediaSourcePrivate;
 class TimeRanges;
 
@@ -52,7 +53,7 @@ public:
     // If already attached, returns false. Otherwise, must be in
     // 'closed' state, and returns true to indicate attachment success.
     // Reattachment allowed by first calling close() (even if already in 'closed').
-    virtual bool attachToElement() = 0;
+    virtual bool attachToElement(HTMLMediaElement*) = 0;
     virtual void setPrivateAndOpen(PassRef<MediaSourcePrivate>) = 0;
     virtual void close() = 0;
     virtual bool isClosed() const = 0;
index 1093fae..c56963f 100644 (file)
@@ -157,11 +157,16 @@ void TimeRanges::add(double start, double end)
 
 bool TimeRanges::contain(double time) const
 {
+    return find(time) != notFound;
+}
+
+size_t TimeRanges::find(double time) const
+{
     for (unsigned n = 0; n < length(); n++) {
         if (time >= start(n, IGNORE_EXCEPTION) && time <= end(n, IGNORE_EXCEPTION))
-            return true;
+            return n;
     }
-    return false;
+    return notFound;
 }
 
 double TimeRanges::nearest(double time) const
index 97f4eb7..72233be 100644 (file)
@@ -54,10 +54,12 @@ public:
     unsigned length() const { return m_ranges.size(); }
     double start(unsigned index, ExceptionCode&) const;
     double end(unsigned index, ExceptionCode&) const;
-    
+
     void add(double start, double end);
     
     bool contain(double time) const;
+
+    size_t find(double time) const;
     
     double nearest(double time) const;
 
index d829c62..077eca0 100644 (file)
@@ -62,7 +62,7 @@ public:
     static const AtomicString& commentaryKeyword();
     virtual const AtomicString& defaultKindKeyword() const OVERRIDE { return emptyAtom; }
 
-    bool enabled() const { return m_enabled; }
+    virtual bool enabled() const OVERRIDE { return m_enabled; }
     virtual void setEnabled(const bool);
 
     virtual void clearClient() OVERRIDE { m_client = 0; }
index ed00580..fefd44e 100644 (file)
@@ -30,9 +30,9 @@
     JSCustomMarkFunction
 ] interface AudioTrack {
     readonly attribute DOMString id;
-    readonly attribute DOMString kind;
+    [CustomSetter] attribute DOMString kind;
     readonly attribute DOMString label;
-    readonly attribute DOMString language;
+    [CustomSetter] attribute DOMString language;
 
     attribute boolean enabled;
 };
index 5b34764..52b57b3 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "Event.h"
 #include "HTMLMediaElement.h"
+#include "SourceBuffer.h"
 #include "TextTrackCueList.h"
 #include "TextTrackList.h"
 #include "TextTrackRegionList.h"
@@ -126,7 +127,7 @@ TextTrack::TextTrack(ScriptExecutionContext* context, TextTrackClient* client, c
     , m_renderedTrackIndex(invalidTrackIndex)
     , m_hasBeenConfigured(false)
 {
-    setKind(kind);
+    setKindInternal(kind);
 }
 
 TextTrack::~TextTrack()
@@ -150,6 +151,11 @@ bool TextTrack::isValidKind(const AtomicString& value) const
     return TextTrack::isValidKindKeyword(value);
 }
 
+bool TextTrack::enabled() const
+{
+    return m_mode != disabledKeyword();
+}
+
 bool TextTrack::isValidKindKeyword(const AtomicString& value)
 {
     if (value == subtitlesKeyword())
@@ -172,7 +178,28 @@ void TextTrack::setKind(const AtomicString& newKind)
 {
     String oldKind = kind();
 
+#if ENABLE(MEDIA_SOURCE)
+    // 10.1 kind, on setting:
+    // 1. If the value being assigned to this attribute does not match one of the text track kinds,
+    // then abort these steps.
+    if (!isValidKindKeyword(newKind))
+        return;
+
+    // 2. Update this attribute to the new value.
+    setKindInternal(newKind);
+
+    // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
+    // event named change at sourceBuffer.textTracks.
+    if (m_sourceBuffer)
+        m_sourceBuffer->textTracks()->scheduleChangeEvent();
+
+    // 4. Queue a task to fire a simple event named change at the TextTrackList object referenced by
+    // the textTracks attribute on the HTMLMediaElement.
+    if (mediaElement())
+        mediaElement()->textTracks()->scheduleChangeEvent();
+#else
     TrackBase::setKind(newKind);
+#endif
 
     if (m_client && oldKind != kind())
         m_client->textTrackKindChanged(this);
@@ -547,6 +574,29 @@ bool TextTrack::isMainProgramContent() const
     return kind() == captionsKeyword();
 }
 
+#if ENABLE(MEDIA_SOURCE)
+void TextTrack::setLanguage(const AtomicString& language)
+{
+    // 11.1 language, on setting:
+    // 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
+    // tag[BCP47], then abort these steps.
+    // FIXME(123926): Validate the BCP47-ness of langague.
+
+    // 2. Update this attribute to the new value.
+    TrackBase::setLanguage(language);
+
+    // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
+    // event named change at sourceBuffer.textTracks.
+    if (m_sourceBuffer)
+        m_sourceBuffer->textTracks()->scheduleChangeEvent();
+
+    // 4. Queue a task to fire a simple event named change at the TextTrackList object referenced by
+    // the textTracks attribute on the HTMLMediaElement.
+    if (mediaElement())
+        mediaElement()->textTracks()->scheduleChangeEvent();
+}
+#endif
+
 } // namespace WebCore
 
 #endif
index 80a88b7..3a36f6d 100644 (file)
@@ -150,6 +150,10 @@ public:
     PassRefPtr<PlatformTextTrack> platformTextTrack();
 #endif
 
+#if ENABLE(MEDIA_SOURCE)
+    virtual void setLanguage(const AtomicString&) OVERRIDE;
+#endif
+
     using RefCounted<TrackBase>::ref;
     using RefCounted<TrackBase>::deref;
 
@@ -164,6 +168,8 @@ protected:
 private:
     virtual bool isValidKind(const AtomicString&) const OVERRIDE;
 
+    virtual bool enabled() const OVERRIDE;
+
     virtual void refEventTarget() OVERRIDE FINAL { ref(); }
     virtual void derefEventTarget() OVERRIDE FINAL { deref(); }
 
index a222804..7c14a6b 100644 (file)
@@ -32,9 +32,9 @@
     OperationsNotDeletable
 ] interface TextTrack {
     readonly attribute DOMString id;
-    readonly attribute DOMString kind;
+    [CustomSetter] attribute DOMString kind;
     readonly attribute DOMString label;
-    readonly attribute DOMString language;
+    [CustomSetter] attribute DOMString language;
 
     attribute DOMString mode;
 
index 70cca47..4a9aa19 100644 (file)
@@ -104,7 +104,7 @@ int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
     return -1;
 }
 
-TextTrack* TextTrackList::item(unsigned index)
+TextTrack* TextTrackList::item(unsigned index) const
 {
     // 4.8.10.12.1 Text track model
     // The text tracks are sorted as follows:
index 45a957d..d9d89f7 100644 (file)
@@ -47,7 +47,9 @@ public:
     int getTrackIndexRelativeToRenderedTracks(TextTrack*);
     virtual bool contains(TrackBase*) const OVERRIDE;
 
-    TextTrack* item(unsigned index);
+    TextTrack* item(unsigned index) const;
+    TextTrack* lastItem() const { return item(length() - 1); }
+
     void append(PassRefPtr<TextTrack>);
     virtual void remove(TrackBase*) OVERRIDE;
 
index 1409cc0..e93e9e9 100644 (file)
@@ -34,6 +34,9 @@ namespace WebCore {
 
 TrackBase::TrackBase(Type type, const AtomicString& id, const AtomicString& label, const AtomicString& language)
     : m_mediaElement(0)
+#if ENABLE(MEDIA_SOURCE)
+    , m_sourceBuffer(0)
+#endif
     , m_id(id)
     , m_label(label)
     , m_language(language)
@@ -53,6 +56,11 @@ Element* TrackBase::element()
 
 void TrackBase::setKind(const AtomicString& kind)
 {
+    setKindInternal(kind);
+}
+
+void TrackBase::setKindInternal(const AtomicString& kind)
+{
     String oldKind = m_kind;
 
     if (isValidKind(kind))
index a0d20ab..509f7a6 100644 (file)
@@ -35,6 +35,7 @@ namespace WebCore {
 
 class Element;
 class HTMLMediaElement;
+class SourceBuffer;
 
 class TrackBase : public RefCounted<TrackBase> {
 public:
@@ -57,18 +58,31 @@ public:
     void setLabel(const AtomicString& label) { m_label = label; }
 
     AtomicString language() const { return m_language; }
-    void setLanguage(const AtomicString& language) { m_language = language; }
+    virtual void setLanguage(const AtomicString& language) { m_language = language; }
 
     virtual void clearClient() = 0;
 
+#if ENABLE(MEDIA_SOURCE)
+    SourceBuffer* sourceBuffer() const { return m_sourceBuffer; }
+    void setSourceBuffer(SourceBuffer* buffer) { m_sourceBuffer = buffer; }
+#endif
+
+    virtual bool enabled() const = 0;
+
 protected:
     TrackBase(Type, const AtomicString& id, const AtomicString& label, const AtomicString& language);
 
     virtual bool isValidKind(const AtomicString&) const = 0;
     virtual const AtomicString& defaultKindKeyword() const = 0;
 
+    void setKindInternal(const AtomicString&);
+
     HTMLMediaElement* m_mediaElement;
 
+#if ENABLE(MEDIA_SOURCE)
+    SourceBuffer* m_sourceBuffer;
+#endif
+
 private:
     Type m_type;
     AtomicString m_id;
index 8bf6c4c..c3df9e6 100644 (file)
@@ -179,4 +179,14 @@ void TrackListBase::asyncEventTimerFired(Timer<TrackListBase>*)
     --m_dispatchingEvents;
 }
 
+bool TrackListBase::isAnyTrackEnabled() const
+{
+    for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
+        TrackBase* track = m_inbandTracks[i].get();
+        if (track->enabled())
+            return true;
+    }
+    return false;
+}
+
 #endif
index b72bc24..7a765e1 100644 (file)
@@ -68,6 +68,8 @@ public:
     // Needs to be public so tracks can call it
     void scheduleChangeEvent();
 
+    bool isAnyTrackEnabled() const;
+
 protected:
     TrackListBase(HTMLMediaElement*, ScriptExecutionContext*);
 
index 4e52744..c0480fe 100644 (file)
 #include "HTMLMediaElement.h"
 #include "VideoTrackList.h"
 
+#if ENABLE(MEDIA_SOURCE)
+#include "SourceBuffer.h"
+#endif
+
 namespace WebCore {
 
 const AtomicString& VideoTrack::alternativeKeyword()
@@ -87,25 +91,25 @@ VideoTrack::VideoTrack(VideoTrackClient* client, PassRefPtr<VideoTrackPrivate> t
 
     switch (m_private->kind()) {
     case VideoTrackPrivate::Alternative:
-        setKind(VideoTrack::alternativeKeyword());
+        setKindInternal(VideoTrack::alternativeKeyword());
         break;
     case VideoTrackPrivate::Captions:
-        setKind(VideoTrack::captionsKeyword());
+        setKindInternal(VideoTrack::captionsKeyword());
         break;
     case VideoTrackPrivate::Main:
-        setKind(VideoTrack::mainKeyword());
+        setKindInternal(VideoTrack::mainKeyword());
         break;
     case VideoTrackPrivate::Sign:
-        setKind(VideoTrack::signKeyword());
+        setKindInternal(VideoTrack::signKeyword());
         break;
     case VideoTrackPrivate::Subtitles:
-        setKind(VideoTrack::subtitlesKeyword());
+        setKindInternal(VideoTrack::subtitlesKeyword());
         break;
     case VideoTrackPrivate::Commentary:
-        setKind(VideoTrack::commentaryKeyword());
+        setKindInternal(VideoTrack::commentaryKeyword());
         break;
     case VideoTrackPrivate::None:
-        setKind(emptyString());
+        setKindInternal(emptyString());
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -184,6 +188,49 @@ void VideoTrack::willRemove(TrackPrivateBase* trackPrivate)
     mediaElement()->removeVideoTrack(this);
 }
 
+#if ENABLE(MEDIA_SOURCE)
+void VideoTrack::setKind(const AtomicString& kind)
+{
+    // 10.1 kind, on setting:
+    // 1. If the value being assigned to this attribute does not match one of the video track kinds,
+    // then abort these steps.
+    if (!isValidKind(kind))
+        return;
+
+    // 2. Update this attribute to the new value.
+    setKindInternal(kind);
+
+    // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
+    // event named change at sourceBuffer.videoTracks.
+    if (m_sourceBuffer)
+        m_sourceBuffer->videoTracks()->scheduleChangeEvent();
+
+    // 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
+    // the videoTracks attribute on the HTMLMediaElement.
+    mediaElement()->videoTracks()->scheduleChangeEvent();
+}
+
+void VideoTrack::setLanguage(const AtomicString& language)
+{
+    // 10.1 language, on setting:
+    // 1. If the value being assigned to this attribute is not an empty string or a BCP 47 language
+    // tag[BCP47], then abort these steps.
+    // FIXME(123926): Validate the BCP47-ness of langague.
+
+    // 2. Update this attribute to the new value.
+    TrackBase::setLanguage(language);
+
+    // 3. If the sourceBuffer attribute on this track is not null, then queue a task to fire a simple
+    // event named change at sourceBuffer.videoTracks.
+    if (m_sourceBuffer)
+        m_sourceBuffer->videoTracks()->scheduleChangeEvent();
+
+    // 4. Queue a task to fire a simple event named change at the VideoTrackList object referenced by
+    // the videoTracks attribute on the HTMLMediaElement.
+    mediaElement()->videoTracks()->scheduleChangeEvent();
+}
+#endif
+
 } // namespace WebCore
 
 #endif
index 1268ce3..b097d8a 100644 (file)
@@ -38,6 +38,7 @@
 
 namespace WebCore {
 
+class MediaDescription;
 class VideoTrack;
 
 class VideoTrackClient {
@@ -70,6 +71,13 @@ public:
 
     size_t inbandTrackIndex();
 
+#if ENABLE(MEDIA_SOURCE)
+    virtual void setKind(const AtomicString&) OVERRIDE;
+    virtual void setLanguage(const AtomicString&) OVERRIDE;
+#endif
+
+    const MediaDescription& description() const;
+
 protected:
     VideoTrack(VideoTrackClient*, PassRefPtr<VideoTrackPrivate> privateTrack);
 
@@ -82,6 +90,8 @@ private:
     virtual void languageChanged(TrackPrivateBase*, const String&) OVERRIDE;
     virtual void willRemove(TrackPrivateBase*) OVERRIDE;
 
+    virtual bool enabled() const OVERRIDE { return selected(); }
+
     bool m_selected;
     VideoTrackClient* m_client;
 
index 1e41a90..53e0da6 100644 (file)
@@ -30,9 +30,9 @@
     JSCustomMarkFunction
 ] interface VideoTrack {
     readonly attribute DOMString id;
-    readonly attribute DOMString kind;
+    [CustomSetter] attribute DOMString kind;
     readonly attribute DOMString label;
-    readonly attribute DOMString language;
+    [CustomSetter] attribute DOMString language;
 
     attribute boolean selected;
 };
diff --git a/Source/WebCore/platform/MediaDescription.h b/Source/WebCore/platform/MediaDescription.h
new file mode 100644 (file)
index 0000000..9cec51f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef MediaDescription_h
+#define MediaDescription_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class MediaDescription : public RefCounted<MediaDescription> {
+public:
+    virtual ~MediaDescription() { }
+
+    virtual AtomicString codec() const = 0;
+    virtual bool isVideo() const = 0;
+    virtual bool isAudio() const = 0;
+    virtual bool isText() const = 0;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/MediaSample.h b/Source/WebCore/platform/MediaSample.h
new file mode 100644 (file)
index 0000000..2f42c51
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef MediaSample_h
+#define MediaSample_h
+
+#include <wtf/MediaTime.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class MockSampleBox;
+
+struct PlatformSample {
+    enum {
+        None,
+        MockSampleBoxType,
+    } type;
+    union {
+        MockSampleBox* mockSampleBox;
+    } sample;
+};
+
+class MediaSample : public RefCounted<MediaSample> {
+public:
+    virtual ~MediaSample() { }
+
+    virtual MediaTime presentationTime() const = 0;
+    virtual MediaTime decodeTime() const = 0;
+    virtual MediaTime duration() const = 0;
+    virtual AtomicString trackID() const = 0;
+
+    enum SampleFlags {
+        None = 0,
+        IsSync = 1 << 0,
+    };
+    virtual SampleFlags flags() const = 0;
+    virtual PlatformSample platformSample() = 0;
+};
+
+}
+
+#endif
index f3a60f8..7d7a488 100644 (file)
@@ -34,6 +34,11 @@ namespace WebCore {
 
 class InbandTextTrackPrivate : public TrackPrivateBase {
 public:
+    enum CueFormat {
+        Generic,
+        WebVTT
+    };
+    static RefPtr<InbandTextTrackPrivate> create(CueFormat format) { return adoptRef(new InbandTextTrackPrivate(format)); }
     virtual ~InbandTextTrackPrivate() { }
 
     void setClient(InbandTextTrackPrivateClient* client) { m_client = client; }
@@ -63,11 +68,12 @@ public:
     virtual bool isMainProgramContent() const { return true; }
     virtual bool isEasyToRead() const { return false; }
     virtual bool isDefault() const { return false; }
+    virtual AtomicString label() const { return emptyAtom; }
+    virtual AtomicString language() const { return emptyAtom; }
+    virtual AtomicString id() const { return emptyAtom; }
+
+    virtual int textTrackIndex() const { return 0; }
 
-    enum CueFormat {
-        Generic,
-        WebVTT
-    };
     CueFormat cueFormat() const { return m_format; }
 
 protected:
index eed776f..f32ab7a 100644 (file)
@@ -32,6 +32,7 @@
 
 #if ENABLE(MEDIA_SOURCE)
 
+#include "MediaPlayer.h"
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
@@ -55,6 +56,9 @@ public:
     enum EndOfStreamStatus { EosNoError, EosNetworkError, EosDecodeError };
     virtual void markEndOfStream(EndOfStreamStatus) = 0;
     virtual void unmarkEndOfStream() = 0;
+
+    virtual MediaPlayer::ReadyState readyState() const = 0;
+    virtual void setReadyState(MediaPlayer::ReadyState) = 0;
 };
 
 }
index 6491da6..ec218f0 100644 (file)
@@ -32,6 +32,7 @@
 
 #if ENABLE(MEDIA_SOURCE)
 
+#include "MediaPlayer.h"
 #include "TimeRanges.h"
 #include <wtf/RefCounted.h>
 
@@ -45,11 +46,12 @@ public:
     virtual ~SourceBufferPrivate() { }
 
     virtual void setClient(SourceBufferPrivateClient*) = 0;
-    virtual PassRefPtr<TimeRanges> buffered() = 0;
     virtual void append(const unsigned char* data, unsigned length) = 0;
     virtual void abort() = 0;
-    virtual bool setTimestampOffset(double) = 0;
     virtual void removedFromMediaSource() = 0;
+
+    virtual MediaPlayer::ReadyState readyState() const = 0;
+    virtual void setReadyState(MediaPlayer::ReadyState) = 0;
 };
 
 }