[MSE] Multiple initialization segments with same codecs in tracks fail validation.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Apr 2014 17:54:59 +0000 (17:54 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Apr 2014 17:54:59 +0000 (17:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=131768

Source/WebCore:
Additional initialization segments added to the same SourceBuffer with the same
codec values will fail validation. Update the validation check to add the correct
codec information for the initial segment, and check against the correct codecs during
the validation step.

Additionally, after validation, if successful update the Audio, Video, and TextTracks
for the SourceBuffer with the updated initialization segment information.

Reviewed by Eric Carlson.

Test: media/media-source/media-source-multiple-initialization-segments.html

* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::appendBufferTimerFired): m_source may have been cleared
    as a result of the append, so check it before using.
(WebCore::SourceBuffer::sourceBufferPrivateDidEndStream): Call streamEndedWithError
    instead of endOfStream as the latter is safe to call within an update.
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment): Ditto.
    Update the track lists if validation succeeds.
(WebCore::SourceBuffer::validateInitializationSegment): Switch the audio and video
    codec checks.

Add the ability for Audio, Video, and InbandTextTracks to replace their private tracks:
* html/track/AudioTrack.cpp:
(WebCore::AudioTrack::AudioTrack): Call updateKindFromPrivate().
(WebCore::AudioTrack::setPrivate):
(WebCore::AudioTrack::updateKindFromPrivate): Split out from constructor.
* html/track/AudioTrack.h:
* html/track/InbandTextTrack.cpp:
(WebCore::InbandTextTrack::InbandTextTrack): Call updateKindFromPrivate().
(WebCore::InbandTextTrack::setPrivate):
(WebCore::InbandTextTrack::setMode): Split up into setModeInternal().
(WebCore::InbandTextTrack::setModeInternal): Broke out from setMode().
(WebCore::InbandTextTrack::updateKindFromPrivate): Split out from constructor.
* html/track/InbandTextTrack.h:
* html/track/TextTrack.h:
(WebCore::TextTrack::isInband): Added, returns false.
* html/track/VideoTrack.cpp:
(WebCore::VideoTrack::VideoTrack): Call updateKindFromPrivate().
(WebCore::VideoTrack::setPrivate):
(WebCore::VideoTrack::updateKindFromPrivate):  Split out from constructor.
* html/track/VideoTrack.h:

LayoutTests:
Reviewed by Eric Carlson.

* media/media-source/media-source-multiple-initialization-segments-expected.txt: Added.
* media/media-source/media-source-multiple-initialization-segments.html: Added.

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt [new file with mode: 0644]
LayoutTests/media/media-source/media-source-multiple-initialization-segments.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/mediasource/SourceBuffer.cpp
Source/WebCore/html/track/AudioTrack.cpp
Source/WebCore/html/track/AudioTrack.h
Source/WebCore/html/track/InbandTextTrack.cpp
Source/WebCore/html/track/InbandTextTrack.h
Source/WebCore/html/track/TextTrack.h
Source/WebCore/html/track/VideoTrack.cpp
Source/WebCore/html/track/VideoTrack.h

index c57bb25..506952f 100644 (file)
@@ -1,3 +1,13 @@
+2014-04-16  Jer Noble  <jer.noble@apple.com>
+
+        [MSE] Multiple initialization segments with same codecs in tracks fail validation.
+        https://bugs.webkit.org/show_bug.cgi?id=131768
+
+        Reviewed by Eric Carlson.
+
+        * media/media-source/media-source-multiple-initialization-segments-expected.txt: Added.
+        * media/media-source/media-source-multiple-initialization-segments.html: Added.
+
 2014-04-17  David Hyatt  <hyatt@apple.com>
 
         [New Multicolumn] Column sets below spanners don't repaint properly.
diff --git a/LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt b/LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt
new file mode 100644 (file)
index 0000000..792a7e0
--- /dev/null
@@ -0,0 +1,14 @@
+
+RUN(video.src = URL.createObjectURL(source))
+EVENT(sourceopen)
+RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(updateend)
+Test that a replacement initialization segment containing a track with the same codec but a different trackID succeeds.
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(updateend)
+Test that a replacement initialization segment containing a track with a different codec but the same trackID fails.
+RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(sourceended)
+END OF TEST
+
diff --git a/LayoutTests/media/media-source/media-source-multiple-initialization-segments.html b/LayoutTests/media/media-source/media-source-multiple-initialization-segments.html
new file mode 100644 (file)
index 0000000..0c8e2d8
--- /dev/null
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>mock-media-source</title>
+    <script src="mock-media-source.js"></script>
+    <script src="../video-test.js"></script>
+    <script>
+    var source;
+    var sourceBuffer;
+    var initSegment;
+
+    if (window.internals)
+        internals.initializeMockMediaSource();
+
+    function runTest() {
+        findMediaElement();
+
+        source = new MediaSource();
+        waitForEventOn(source, 'sourceopen', sourceOpen);
+        waitForEventOn(source, 'sourceended', sourceEnded);
+        run('video.src = URL.createObjectURL(source)');
+    }
+
+    function sourceOpen() {
+        run('sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock")');
+
+        waitForEventOn(sourceBuffer, 'updateend', firstUpdate, false, true);
+        initSegment = makeAInit(100, [
+            makeATrack(1, 'mock', TRACK_KIND.VIDEO),
+        ]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+    }
+
+    function sourceEnded() {
+        if (!expected)
+            logResult(Failed, 'Unexpected "sourceended" event');
+        endTest();
+    }
+    
+    function firstUpdate() {
+        consoleWrite('Test that a replacement initialization segment containing a track with the same codec but a different trackID succeeds.')
+        waitForEventOn(sourceBuffer, 'updateend', secondUpdate, false, true);
+        initSegment = makeAInit(100, [
+            makeATrack(2, 'mock', TRACK_KIND.VIDEO),
+        ]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+    }
+
+    function secondUpdate() {
+        consoleWrite('Test that a replacement initialization segment containing a track with a different codec but the same trackID fails.')
+        waitForEventOn(sourceBuffer, 'updateend', endTest, false, true);
+        expected = true;
+        initSegment = makeAInit(100, [
+            makeATrack(2, '!moc', TRACK_KIND.VIDEO),
+        ]);
+        run('sourceBuffer.appendBuffer(initSegment)');
+    }
+
+    </script>
+</head>
+<body onload="runTest()">
+    <video></video>
+</body>
+</html>
index 52c4d7b..5e135e1 100644 (file)
@@ -1,3 +1,51 @@
+2014-04-16  Jer Noble  <jer.noble@apple.com>
+
+        [MSE] Multiple initialization segments with same codecs in tracks fail validation.
+        https://bugs.webkit.org/show_bug.cgi?id=131768
+
+        Additional initialization segments added to the same SourceBuffer with the same
+        codec values will fail validation. Update the validation check to add the correct
+        codec information for the initial segment, and check against the correct codecs during
+        the validation step.
+
+        Additionally, after validation, if successful update the Audio, Video, and TextTracks
+        for the SourceBuffer with the updated initialization segment information.
+
+        Reviewed by Eric Carlson.
+
+        Test: media/media-source/media-source-multiple-initialization-segments.html
+
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::appendBufferTimerFired): m_source may have been cleared
+            as a result of the append, so check it before using.
+        (WebCore::SourceBuffer::sourceBufferPrivateDidEndStream): Call streamEndedWithError
+            instead of endOfStream as the latter is safe to call within an update.
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment): Ditto.
+            Update the track lists if validation succeeds.
+        (WebCore::SourceBuffer::validateInitializationSegment): Switch the audio and video
+            codec checks.
+
+        Add the ability for Audio, Video, and InbandTextTracks to replace their private tracks:
+        * html/track/AudioTrack.cpp:
+        (WebCore::AudioTrack::AudioTrack): Call updateKindFromPrivate().
+        (WebCore::AudioTrack::setPrivate):
+        (WebCore::AudioTrack::updateKindFromPrivate): Split out from constructor.
+        * html/track/AudioTrack.h:
+        * html/track/InbandTextTrack.cpp:
+        (WebCore::InbandTextTrack::InbandTextTrack): Call updateKindFromPrivate().
+        (WebCore::InbandTextTrack::setPrivate):
+        (WebCore::InbandTextTrack::setMode): Split up into setModeInternal().
+        (WebCore::InbandTextTrack::setModeInternal): Broke out from setMode().
+        (WebCore::InbandTextTrack::updateKindFromPrivate): Split out from constructor.
+        * html/track/InbandTextTrack.h:
+        * html/track/TextTrack.h:
+        (WebCore::TextTrack::isInband): Added, returns false.
+        * html/track/VideoTrack.cpp:
+        (WebCore::VideoTrack::VideoTrack): Call updateKindFromPrivate().
+        (WebCore::VideoTrack::setPrivate):
+        (WebCore::VideoTrack::updateKindFromPrivate):  Split out from constructor.
+        * html/track/VideoTrack.h:
+
 2014-04-17  David Hyatt  <hyatt@apple.com>
 
         [New Multicolumn] Column sets below spanners don't repaint properly.
index 4ad240d..650b381 100644 (file)
@@ -508,7 +508,8 @@ 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();
+    if (m_source)
+        m_source->monitorSourceBuffers();
     for (auto iter = m_trackBufferMap.begin(), end = m_trackBufferMap.end(); iter != end; ++iter)
         provideMediaData(iter->value, iter->key);
 }
@@ -645,7 +646,7 @@ void SourceBuffer::setActive(bool active)
 void SourceBuffer::sourceBufferPrivateDidEndStream(SourceBufferPrivate*, const WTF::AtomicString& error)
 {
     if (!isRemoved())
-        m_source->endOfStream(error, IgnorableExceptionCode());
+        m_source->streamEndedWithError(error, IgnorableExceptionCode());
 }
 
 void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivate*, const InitializationSegment& segment)
@@ -668,17 +669,51 @@ void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBuff
     // 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());
+        m_source->streamEndedWithError(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());
+            m_source->streamEndedWithError(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
+        ASSERT(segment.audioTracks.size() == audioTracks()->length());
+        for (auto& audioTrackInfo : segment.audioTracks) {
+            if (audioTracks()->length() == 1) {
+                audioTracks()->item(0)->setPrivate(audioTrackInfo.track);
+                break;
+            }
+
+            auto audioTrack = audioTracks()->getTrackById(audioTrackInfo.track->id());
+            ASSERT(audioTrack);
+            audioTrack->setPrivate(audioTrackInfo.track);
+        }
+
+        ASSERT(segment.videoTracks.size() == videoTracks()->length());
+        for (auto& videoTrackInfo : segment.videoTracks) {
+            if (videoTracks()->length() == 1) {
+                videoTracks()->item(0)->setPrivate(videoTrackInfo.track);
+                break;
+            }
+
+            auto videoTrack = videoTracks()->getTrackById(videoTrackInfo.track->id());
+            ASSERT(videoTrack);
+            videoTrack->setPrivate(videoTrackInfo.track);
+        }
+
+        ASSERT(segment.textTracks.size() == textTracks()->length());
+        for (auto& textTrackInfo : segment.textTracks) {
+            if (textTracks()->length() == 1) {
+                toInbandTextTrack(textTracks()->item(0))->setPrivate(textTrackInfo.track);
+                break;
+            }
+
+            auto textTrack = textTracks()->getTrackById(textTrackInfo.track->id());
+            ASSERT(textTrack);
+            toInbandTextTrack(textTrack)->setPrivate(textTrackInfo.track);
+        }
     }
 
     // 4. Let active track flag equal false.
@@ -726,6 +761,8 @@ void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBuff
 
             // 5.2.9 Add the track description for this track to the track buffer.
             trackBuffer.description = it->description;
+
+            m_audioCodecs.append(trackBuffer.description->codec());
         }
 
         // 5.3 For each video track in the initialization segment, run following steps:
@@ -764,6 +801,8 @@ void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBuff
 
             // 5.3.9 Add the track description for this track to the track buffer.
             trackBuffer.description = it->description;
+
+            m_videoCodecs.append(trackBuffer.description->codec());
         }
 
         // 5.4 For each text track in the initialization segment, run following steps:
@@ -797,6 +836,8 @@ void SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(SourceBuff
 
             // 5.4.8 Add the track description for this track to the track buffer.
             trackBuffer.description = it->description;
+
+            m_textCodecs.append(trackBuffer.description->codec());
         }
 
         // 5.5 If active track flag equals true, then run the following steps:
@@ -844,12 +885,12 @@ bool SourceBuffer::validateInitializationSegment(const InitializationSegment& se
 
     //   * 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()))
+        if (!m_audioCodecs.contains(it->description->codec()))
             return false;
     }
 
     for (auto it = segment.videoTracks.begin(); it != segment.videoTracks.end(); ++it) {
-        if (!m_audioCodecs.contains(it->description->codec()))
+        if (!m_videoCodecs.contains(it->description->codec()))
             return false;
     }
 
index 4f2dd84..bdbec6f 100644 (file)
@@ -84,33 +84,7 @@ AudioTrack::AudioTrack(AudioTrackClient* client, PassRefPtr<AudioTrackPrivate> t
     , m_private(trackPrivate)
 {
     m_private->setClient(this);
-
-    switch (m_private->kind()) {
-    case AudioTrackPrivate::Alternative:
-        setKind(AudioTrack::alternativeKeyword());
-        break;
-    case AudioTrackPrivate::Description:
-        setKind(AudioTrack::descriptionKeyword());
-        break;
-    case AudioTrackPrivate::Main:
-        setKind(AudioTrack::mainKeyword());
-        break;
-    case AudioTrackPrivate::MainDesc:
-        setKind(AudioTrack::mainDescKeyword());
-        break;
-    case AudioTrackPrivate::Translation:
-        setKind(AudioTrack::translationKeyword());
-        break;
-    case AudioTrackPrivate::Commentary:
-        setKind(AudioTrack::commentaryKeyword());
-        break;
-    case AudioTrackPrivate::None:
-        setKind(emptyString());
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-        break;
-    }
+    updateKindFromPrivate();
 }
 
 AudioTrack::~AudioTrack()
@@ -118,6 +92,22 @@ AudioTrack::~AudioTrack()
     m_private->setClient(0);
 }
 
+void AudioTrack::setPrivate(PassRefPtr<AudioTrackPrivate> trackPrivate)
+{
+    ASSERT(m_private);
+    ASSERT(trackPrivate);
+
+    if (m_private == trackPrivate)
+        return;
+
+    m_private->setClient(0);
+    m_private = trackPrivate;
+    m_private->setClient(this);
+
+    m_private->setEnabled(m_enabled);
+    updateKindFromPrivate();
+}
+
 bool AudioTrack::isValidKind(const AtomicString& value) const
 {
     if (value == alternativeKeyword())
@@ -184,6 +174,36 @@ void AudioTrack::willRemove(TrackPrivateBase* trackPrivate)
     mediaElement()->removeAudioTrack(this);
 }
 
+void AudioTrack::updateKindFromPrivate()
+{
+    switch (m_private->kind()) {
+    case AudioTrackPrivate::Alternative:
+        setKind(AudioTrack::alternativeKeyword());
+        break;
+    case AudioTrackPrivate::Description:
+        setKind(AudioTrack::descriptionKeyword());
+        break;
+    case AudioTrackPrivate::Main:
+        setKind(AudioTrack::mainKeyword());
+        break;
+    case AudioTrackPrivate::MainDesc:
+        setKind(AudioTrack::mainDescKeyword());
+        break;
+    case AudioTrackPrivate::Translation:
+        setKind(AudioTrack::translationKeyword());
+        break;
+    case AudioTrackPrivate::Commentary:
+        setKind(AudioTrack::commentaryKeyword());
+        break;
+    case AudioTrackPrivate::None:
+        setKind(emptyString());
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
 } // namespace WebCore
 
 #endif
index d9d41be..0602295 100644 (file)
@@ -69,6 +69,8 @@ public:
 
     size_t inbandTrackIndex();
 
+    void setPrivate(PassRefPtr<AudioTrackPrivate>);
+
 protected:
     AudioTrack(AudioTrackClient*, PassRefPtr<AudioTrackPrivate>);
 
@@ -81,6 +83,8 @@ private:
     virtual void languageChanged(TrackPrivateBase*, const AtomicString&) override;
     virtual void willRemove(TrackPrivateBase*) override;
 
+    void updateKindFromPrivate();
+
     bool m_enabled;
     AudioTrackClient* m_client;
 
index c488a89..7100b86 100644 (file)
@@ -65,31 +65,7 @@ InbandTextTrack::InbandTextTrack(ScriptExecutionContext* context, TextTrackClien
     , m_private(trackPrivate)
 {
     m_private->setClient(this);
-    
-    switch (m_private->kind()) {
-    case InbandTextTrackPrivate::Subtitles:
-        setKind(TextTrack::subtitlesKeyword());
-        break;
-    case InbandTextTrackPrivate::Captions:
-        setKind(TextTrack::captionsKeyword());
-        break;
-    case InbandTextTrackPrivate::Descriptions:
-        setKind(TextTrack::descriptionsKeyword());
-        break;
-    case InbandTextTrackPrivate::Chapters:
-        setKind(TextTrack::chaptersKeyword());
-        break;
-    case InbandTextTrackPrivate::Metadata:
-        setKind(TextTrack::metadataKeyword());
-        break;
-    case InbandTextTrackPrivate::Forced:
-        setKind(TextTrack::forcedKeyword());
-        break;
-    case InbandTextTrackPrivate::None:
-    default:
-        ASSERT_NOT_REACHED();
-        break;
-    }
+    updateKindFromPrivate();
 }
 
 InbandTextTrack::~InbandTextTrack()
@@ -97,10 +73,30 @@ InbandTextTrack::~InbandTextTrack()
     m_private->setClient(0);
 }
 
+void InbandTextTrack::setPrivate(PassRefPtr<InbandTextTrackPrivate> trackPrivate)
+{
+    ASSERT(m_private);
+    ASSERT(trackPrivate);
+
+    if (m_private == trackPrivate)
+        return;
+
+    m_private->setClient(0);
+    m_private = trackPrivate;
+    m_private->setClient(this);
+
+    setModeInternal(mode());
+    updateKindFromPrivate();
+}
+
 void InbandTextTrack::setMode(const AtomicString& mode)
 {
     TextTrack::setMode(mode);
+    setModeInternal(mode);
+}
 
+void InbandTextTrack::setModeInternal(const AtomicString& mode)
+{
     if (mode == TextTrack::disabledKeyword())
         m_private->setMode(InbandTextTrackPrivate::Disabled);
     else if (mode == TextTrack::hiddenKeyword())
@@ -189,6 +185,34 @@ void InbandTextTrack::willRemove(TrackPrivateBase* trackPrivate)
     mediaElement()->removeTextTrack(this);
 }
 
+void InbandTextTrack::updateKindFromPrivate()
+{
+    switch (m_private->kind()) {
+    case InbandTextTrackPrivate::Subtitles:
+        setKind(TextTrack::subtitlesKeyword());
+        break;
+    case InbandTextTrackPrivate::Captions:
+        setKind(TextTrack::captionsKeyword());
+        break;
+    case InbandTextTrackPrivate::Descriptions:
+        setKind(TextTrack::descriptionsKeyword());
+        break;
+    case InbandTextTrackPrivate::Chapters:
+        setKind(TextTrack::chaptersKeyword());
+        break;
+    case InbandTextTrackPrivate::Metadata:
+        setKind(TextTrack::metadataKeyword());
+        break;
+    case InbandTextTrackPrivate::Forced:
+        setKind(TextTrack::forcedKeyword());
+        break;
+    case InbandTextTrackPrivate::None:
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
 } // namespace WebCore
 
 #endif
index 924b126..cd47fca 100644 (file)
@@ -50,9 +50,16 @@ public:
 
     virtual AtomicString inBandMetadataTrackDispatchType() const;
 
+    void setPrivate(PassRefPtr<InbandTextTrackPrivate>);
+
+    virtual bool isInband() const override { return true; }
+
 protected:
     InbandTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
 
+    void setModeInternal(const AtomicString&);
+    void updateKindFromPrivate();
+
     RefPtr<InbandTextTrackPrivate> m_private;
 
 private:
@@ -75,6 +82,8 @@ private:
 #endif
 };
 
+TYPE_CASTS_BASE(InbandTextTrack, TextTrack, track, track->isInband(), track.isInband());
+
 } // namespace WebCore
 
 #endif
index 5594598..29d8c77 100644 (file)
@@ -156,6 +156,8 @@ public:
     virtual void setLanguage(const AtomicString&) override;
 #endif
 
+    virtual bool isInband() const { return false; }
+
     using RefCounted<TrackBase>::ref;
     using RefCounted<TrackBase>::deref;
 
index 5997823..bbdc90d 100644 (file)
@@ -88,33 +88,7 @@ VideoTrack::VideoTrack(VideoTrackClient* client, PassRefPtr<VideoTrackPrivate> t
     , m_private(trackPrivate)
 {
     m_private->setClient(this);
-
-    switch (m_private->kind()) {
-    case VideoTrackPrivate::Alternative:
-        setKindInternal(VideoTrack::alternativeKeyword());
-        break;
-    case VideoTrackPrivate::Captions:
-        setKindInternal(VideoTrack::captionsKeyword());
-        break;
-    case VideoTrackPrivate::Main:
-        setKindInternal(VideoTrack::mainKeyword());
-        break;
-    case VideoTrackPrivate::Sign:
-        setKindInternal(VideoTrack::signKeyword());
-        break;
-    case VideoTrackPrivate::Subtitles:
-        setKindInternal(VideoTrack::subtitlesKeyword());
-        break;
-    case VideoTrackPrivate::Commentary:
-        setKindInternal(VideoTrack::commentaryKeyword());
-        break;
-    case VideoTrackPrivate::None:
-        setKindInternal(emptyString());
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-        break;
-    }
+    updateKindFromPrivate();
 }
 
 VideoTrack::~VideoTrack()
@@ -122,6 +96,22 @@ VideoTrack::~VideoTrack()
     m_private->setClient(0);
 }
 
+void VideoTrack::setPrivate(PassRefPtr<VideoTrackPrivate> trackPrivate)
+{
+    ASSERT(m_private);
+    ASSERT(trackPrivate);
+
+    if (m_private == trackPrivate)
+        return;
+
+    m_private->setClient(nullptr);
+    m_private = trackPrivate;
+    m_private->setClient(this);
+
+    m_private->setSelected(m_selected);
+    updateKindFromPrivate();
+}
+
 bool VideoTrack::isValidKind(const AtomicString& value) const
 {
     if (value == alternativeKeyword())
@@ -231,6 +221,36 @@ void VideoTrack::setLanguage(const AtomicString& language)
 }
 #endif
 
+void VideoTrack::updateKindFromPrivate()
+{
+    switch (m_private->kind()) {
+    case VideoTrackPrivate::Alternative:
+        setKindInternal(VideoTrack::alternativeKeyword());
+        break;
+    case VideoTrackPrivate::Captions:
+        setKindInternal(VideoTrack::captionsKeyword());
+        break;
+    case VideoTrackPrivate::Main:
+        setKindInternal(VideoTrack::mainKeyword());
+        break;
+    case VideoTrackPrivate::Sign:
+        setKindInternal(VideoTrack::signKeyword());
+        break;
+    case VideoTrackPrivate::Subtitles:
+        setKindInternal(VideoTrack::subtitlesKeyword());
+        break;
+    case VideoTrackPrivate::Commentary:
+        setKindInternal(VideoTrack::commentaryKeyword());
+        break;
+    case VideoTrackPrivate::None:
+        setKindInternal(emptyString());
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
 } // namespace WebCore
 
 #endif
index fa7ad79..27a5102 100644 (file)
@@ -77,6 +77,8 @@ public:
 
     const MediaDescription& description() const;
 
+    void setPrivate(PassRefPtr<VideoTrackPrivate>);
+
 protected:
     VideoTrack(VideoTrackClient*, PassRefPtr<VideoTrackPrivate> privateTrack);
 
@@ -91,6 +93,8 @@ private:
 
     virtual bool enabled() const override { return selected(); }
 
+    void updateKindFromPrivate();
+
     bool m_selected;
     VideoTrackClient* m_client;