Source/WebCore: [GStreamer] support in-band text tracks
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Aug 2013 20:17:27 +0000 (20:17 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Aug 2013 20:17:27 +0000 (20:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=103771

Patch by Brendan Long <b.long@cablelabs.com> on 2013-08-30
Reviewed by Eric Carlson.

Tests: New tests added because existing tests were too specific.
   media/track/in-band/track-in-band-kate-ogg-cues-added-once.html
   media/track/in-band/track-in-band-kate-ogg-kind.html
   media/track/in-band/track-in-band-kate-ogg-language.html
   media/track/in-band/track-in-band-kate-ogg-mode.html
   media/track/in-band/track-in-band-kate-ogg-style.html
   media/track/in-band/track-in-band-kate-ogg-track-order.html
   media/track/in-band/track-in-band-srt-mkv-cues-added-once.html
   media/track/in-band/track-in-band-srt-mkv-kind.html
   media/track/in-band/track-in-band-srt-mkv-language.html
   media/track/in-band/track-in-band-srt-mkv-mode.html
   media/track/in-band/track-in-band-srt-mkv-style.html
   media/track/in-band/track-in-band-srt-mkv-track-order.html

* CMakeLists.txt: Add InbandTextTrackPrivateGStreamer, InbandGenericTextTrack, InbandWebVTTTextTrack, and TextCombinerGStreamer files.
* GNUmakefile.list.am: Same.
* PlatformEfl.cmake: Same.
* Target.pri: Same.
* WebCore.vcxproj/WebCore.vcxproj: Same.
* WebCore.vcxproj/WebCore.vcxproj.filters: Same.
* WebCore.xcodeproj/project.pbxproj: Same.
* html/track/InbandGenericTextTrack.cpp: Split out code for handling generic cues.
(WebCore::GenericTextTrackCueMap::GenericTextTrackCueMap): Move from InbandTextTrack.
(WebCore::GenericTextTrackCueMap::~GenericTextTrackCueMap): Same.
(WebCore::GenericTextTrackCueMap::add): Same.
(WebCore::GenericTextTrackCueMap::find): Same.
(WebCore::GenericTextTrackCueMap::remove): Same.
(WebCore::InbandGenericTextTrack::create): Same.
(WebCore::InbandGenericTextTrack::updateCueFromCueData): Same.
(WebCore::InbandGenericTextTrack::addGenericCue): Same.
(WebCore::InbandGenericTextTrack::updateGenericCue): Same.
(WebCore::InbandGenericTextTrack::removeGenericCue): Same.
(WebCore::InbandGenericTextTrack::removeCue): Same.
(WebCore::InbandGenericTextTrack::InbandGenericTextTrack): Empty.
(WebCore::InbandGenericTextTrack::~InbandGenericTextTrack): Empty.
* html/track/InbandGenericTextTrack.h: Copied from Source/WebCore/html/track/InbandTextTrack.h.
The only addition is the ASSERT_NOT_REACHED() for WebVTT cues.
* html/track/InbandTextTrack.cpp: Add label and language changed callbacks.
(WebCore::InbandTextTrack::create): Return a generic or WebVTT text track based on the private CueFormat.
(WebCore::InbandTextTrack::labelChanged): Added.
(WebCore::InbandTextTrack::languageChanged): Added.
* html/track/InbandTextTrack.h: Add label and language changed callbacks.
* html/track/InbandWebVTTTextTrack.cpp: Added, based on InbandTextTrack.
(WebCore::InbandWebVTTTextTrack::create): Same.
(WebCore::InbandWebVTTTextTrack::InbandWebVTTTextTrack): Empty.
(WebCore::InbandWebVTTTextTrack::~InbandWebVTTTextTrack): Empty.
(WebCore::InbandWebVTTTextTrack::parseWebVTTCueData): Sends data to a WebVTTParser.
(WebCore::InbandWebVTTTextTrack::newCuesParsed): Adds cues when WebVTTParser parses them.
(WebCore::InbandWebVTTTextTrack::fileFailedToParse): Prints a warning when WebVTTParser has a problem.
* html/track/InbandWebVTTTextTrack.h: Added.
* platform/graphics/InbandTextTrackPrivate.h:
(WebCore::InbandTextTrackPrivate::cueFormat): For determining if the track will have generic or WebVTT cues.
(WebCore::InbandTextTrackPrivate::InbandTextTrackPrivate): Pass CueFormat in the constructor.
* platform/graphics/InbandTextTrackPrivateClient.h: Same.
* platform/graphics/avfoundation/InbandTextTrackPrivateAVF.cpp:
(WebCore::InbandTextTrackPrivateAVF::InbandTextTrackPrivateAVF): Pass CueFormat (Generic) to InbandTextTrackPrivate.
* platform/graphics/gstreamer/GRefPtrGStreamer.cpp: Add GRefPtr specializations for GstSample and GstEvent.
* platform/graphics/gstreamer/GRefPtrGStreamer.h: Same.
* platform/graphics/gstreamer/GStreamerUtilities.h: Add WARN_MEDIA_MESSAGE.
* platform/graphics/gstreamer/GStreamerVersioning.h: Add a function to check GStreamer version at runtime.
* platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp: Added.
(WebCore::textTrackPrivateEventCallback): Watches for tag and stream start events.
(WebCore::textTrackPrivateSampleTimeoutCallback): See notifyTrackOfSample();
(WebCore::textTrackPrivateStreamTimeoutCallback): See notifyTrackOfStreamChanged();
(WebCore::textTrackPrivateTagsChangeTimeoutCallback): See notifyTrackOfTagsChanged();
(WebCore::InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer): Initializes tags and stream and sets up event callback.
(WebCore::InbandTextTrackPrivateGStreamer::~InbandTextTrackPrivateGStreamer): Calls disconnect:
(WebCore::InbandTextTrackPrivateGStreamer::disconnect): Removes signal handlers and frees some memory.
(WebCore::InbandTextTrackPrivateGStreamer::handleSample): Adds samples to a list and sets up callback.
(WebCore::InbandTextTrackPrivateGStreamer::streamChanged): Sets up callback.
(WebCore::InbandTextTrackPrivateGStreamer::tagsChanged): Same.
(WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfSample): Parses all queued samples with WebVTTParser.
(WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfStreamChanged): Keeps track of current stream.
(WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfTagsChanged): Sets label and language from tags.
* platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h: Added.
(WebCore::InbandTextTrackPrivateGStreamer::create): Basic RefPtr create function.
(WebCore::InbandTextTrackPrivateGStreamer::pad): Returns the pad this track is associated with (used
to determine if a playbin text stream has already been associated with a text track).
(WebCore::InbandTextTrackPrivateGStreamer::setIndex): Sets the track index (used for sorting).
(WebCore::InbandTextTrackPrivateGStreamer::streamId): Returns the stream ID (used to handle new samples).
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::mediaPlayerPrivateTextChangedCallback): Called for playbin "text-changed" event. See textChanged().
(WebCore::mediaPlayerPrivateTextChangeTimeoutCallback): See notifyPlayerOfText().
(WebCore::mediaPlayerPrivateNewTextSampleCallback): See newTextSample().
(WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer): Initialize m_textTimerHandler.
(WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer): Disconnect text tracks (they don't necessarily
get freed here, since a script could hold a reference).
(WebCore::MediaPlayerPrivateGStreamer::textChanged): Setup callback for notifyPlayerOfText.
(WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfText): Create text tracks.
(WebCore::MediaPlayerPrivateGStreamer::newTextSample): Handle new samples by giving them to a text track
with a matching stream. This method is syncryonous because we need to get the stream start sticky event
immediately.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
* platform/graphics/gstreamer/TextCombinerGStreamer.cpp: Added. This element forwards buffers from all
of its input pads, but also converts plain text to WebVTT as needed.
(webkit_text_combiner_init): Setup internal funnel.
(webkitTextCombinerPadEvent): If the caps are plain text make sure we have a webvttenv, otherwise connect
directly to the funnel.
(webkitTextCombinerRequestNewPad): Setup ghostpad and event callback.
(webkitTextCombinerReleasePad): Release pad and optional associated webvttenc.
(webkit_text_combiner_class_init): Setup pad templates and request/release pad functions.
(webkitTextCombinerNew): Returns a new WebKitTextCombiner.
* platform/graphics/gstreamer/TextCombinerGStreamer.h: Added.
* platform/graphics/gstreamer/TextSinkGStreamer.cpp: Added.
(webkit_text_sink_init): Set sync=false.
(webkitTextSinkGetProperty): Ignore sync property.
(webkitTextSinkSetProperty): Same.
(webkitTextSinkQuery): Ignore position and duration queries, forward everything else to appsink.
(webkit_text_sink_class_init): Setup property and query functions.
(webkitTextSinkNew): Return a new WebKitTextSink.
* platform/graphics/gstreamer/TextSinkGStreamer.h: Added.

LayoutTests: <https://webkit.org/b/103771> [GStreamer] support in-band text tracks

Patch by Brendan Long <b.long@cablelabs.com> on 2013-08-30
Reviewed by Eric Carlson.

* media/content/counting-subtitled-kate.ogv: Added.
* media/content/counting-subtitled-srt.mkv: Added.
* media/in-band-cues.js: Added.
* media/track/in-band/track-in-band-kate-ogg-cues-added-once-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-cues-added-once.html: Added.
* media/track/in-band/track-in-band-kate-ogg-kind-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-kind.html: Added.
* media/track/in-band/track-in-band-kate-ogg-language-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-language.html: Added.
* media/track/in-band/track-in-band-kate-ogg-mode-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-mode.html: Added.
* media/track/in-band/track-in-band-kate-ogg-style-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-style.html: Added.
* media/track/in-band/track-in-band-kate-ogg-track-order-expected.txt: Added.
* media/track/in-band/track-in-band-kate-ogg-track-order.html: Added.
* media/track/in-band/track-in-band-srt-mkv-cues-added-once-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-cues-added-once.html: Added.
* media/track/in-band/track-in-band-srt-mkv-kind-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-kind.html: Added.
* media/track/in-band/track-in-band-srt-mkv-language-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-language.html: Added.
* media/track/in-band/track-in-band-srt-mkv-mode-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-mode.html: Added.
* media/track/in-band/track-in-band-srt-mkv-style-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-style.html: Added.
* media/track/in-band/track-in-band-srt-mkv-track-order-expected.txt: Added.
* media/track/in-band/track-in-band-srt-mkv-track-order.html: Added.
* platform/mac/TestExpectations: Skip MKV and OGG tests.

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

59 files changed:
LayoutTests/ChangeLog
LayoutTests/media/content/counting-subtitled-kate.ogv [new file with mode: 0644]
LayoutTests/media/content/counting-subtitled-srt.mkv [new file with mode: 0644]
LayoutTests/media/in-band-cues.js [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-language-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-language.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-style-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-style.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-language-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-language.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-style-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-style.html [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order-expected.txt [new file with mode: 0644]
LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order.html [new file with mode: 0644]
LayoutTests/platform/mac/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/PlatformEfl.cmake
Source/WebCore/Target.pri
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/track/InbandGenericTextTrack.cpp [new file with mode: 0644]
Source/WebCore/html/track/InbandGenericTextTrack.h [new file with mode: 0644]
Source/WebCore/html/track/InbandTextTrack.cpp
Source/WebCore/html/track/InbandTextTrack.h
Source/WebCore/html/track/InbandWebVTTTextTrack.cpp [new file with mode: 0644]
Source/WebCore/html/track/InbandWebVTTTextTrack.h [new file with mode: 0644]
Source/WebCore/platform/graphics/InbandTextTrackPrivate.h
Source/WebCore/platform/graphics/InbandTextTrackPrivateClient.h
Source/WebCore/platform/graphics/avfoundation/InbandTextTrackPrivateAVF.cpp
Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/GRefPtrGStreamer.h
Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.h
Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h
Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.h [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.h [new file with mode: 0644]

index 36f10d70568b962a76db396b15d1db0114554399..5a50b0eeebc5613e0df534944b37cd00fce9532b 100644 (file)
@@ -1,3 +1,38 @@
+2013-08-30  Brendan Long  <b.long@cablelabs.com>
+
+        <https://webkit.org/b/103771> [GStreamer] support in-band text tracks
+
+        Reviewed by Eric Carlson.
+
+        * media/content/counting-subtitled-kate.ogv: Added.
+        * media/content/counting-subtitled-srt.mkv: Added.
+        * media/in-band-cues.js: Added.
+        * media/track/in-band/track-in-band-kate-ogg-cues-added-once-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-cues-added-once.html: Added.
+        * media/track/in-band/track-in-band-kate-ogg-kind-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-kind.html: Added.
+        * media/track/in-band/track-in-band-kate-ogg-language-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-language.html: Added.
+        * media/track/in-band/track-in-band-kate-ogg-mode-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-mode.html: Added.
+        * media/track/in-band/track-in-band-kate-ogg-style-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-style.html: Added.
+        * media/track/in-band/track-in-band-kate-ogg-track-order-expected.txt: Added.
+        * media/track/in-band/track-in-band-kate-ogg-track-order.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-cues-added-once-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-cues-added-once.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-kind-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-kind.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-language-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-language.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-mode-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-mode.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-style-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-style.html: Added.
+        * media/track/in-band/track-in-band-srt-mkv-track-order-expected.txt: Added.
+        * media/track/in-band/track-in-band-srt-mkv-track-order.html: Added.
+        * platform/mac/TestExpectations: Skip MKV and OGG tests.
+
 2013-08-30  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: inspector/storage-panel-dom-storage-update.html is flakey on the bots
diff --git a/LayoutTests/media/content/counting-subtitled-kate.ogv b/LayoutTests/media/content/counting-subtitled-kate.ogv
new file mode 100644 (file)
index 0000000..523973c
Binary files /dev/null and b/LayoutTests/media/content/counting-subtitled-kate.ogv differ
diff --git a/LayoutTests/media/content/counting-subtitled-srt.mkv b/LayoutTests/media/content/counting-subtitled-srt.mkv
new file mode 100644 (file)
index 0000000..4c08ec0
Binary files /dev/null and b/LayoutTests/media/content/counting-subtitled-srt.mkv differ
diff --git a/LayoutTests/media/in-band-cues.js b/LayoutTests/media/in-band-cues.js
new file mode 100644 (file)
index 0000000..4fe1577
--- /dev/null
@@ -0,0 +1,192 @@
+function testAttribute(uri, attribute, values)
+{
+    function canplaythrough()
+    {
+        consoleWrite("<br><i>** Check in-band kind attributes</i>");
+        testExpected("video.textTracks.length", values.length);
+        for (var i = 0; i < values.length; ++i) {
+            testExpected("video.textTracks[" + i + "]." + attribute, values[i]);
+        }
+
+        consoleWrite("");
+        endTest();
+    }
+
+    findMediaElement();
+    video.src = uri;
+    waitForEvent('canplaythrough', canplaythrough);
+}
+
+function testCuesAddedOnce(uri)
+{
+    var seekedCount = 0;
+    var cuesStarts = [];
+
+    function pollProgress()
+    {
+        if (video.currentTime < 2)
+            return;
+
+        testExpected("inbandTrack1.cues.length", 0, ">");
+
+        if (!seekedCount) {
+            // Collect the start times of all cues, seek back to the\beginning and play
+            // the same segment of the video file.
+            run("video.pause()");
+            for (var i = 0; i < inbandTrack1.cues.length; ++i)
+                cuesStarts.push(inbandTrack1.cues[i].startTime);
+            run("video.currentTime = 0");
+            run("video.play()");
+            consoleWrite("");
+            return;
+        }
+
+        run("video.pause()");
+        try {
+            var success = true;
+            for (var i = 0; i < cuesStarts.length; ++i) {
+                if (inbandTrack1.cues[i].startTime != cuesStarts[i]) {
+                    // Since we don't know the exact number of cues, only print
+                    // output if the test fails.
+                    testExpected("inbandTrack1.cues[" + i + "].startTime", cuesStarts[i]);
+                    success = false;
+                }
+            }
+            logResult(success, "Test all cues are equal");
+            endTest();
+        } catch (e) {
+            failTest(e);
+        }
+    }
+
+    function canplaythrough()
+    {
+        waitForEvent('seeked', function() { ++seekedCount; });
+        setInterval(pollProgress, 100);
+
+        consoleWrite("<br><i>** Setting track 1 to showing</i>");
+        run("inbandTrack1 = video.textTracks[0]");
+        run("inbandTrack1.mode = 'showing'");
+        run("video.play()");
+    }
+
+    findMediaElement();
+    video.src = uri;
+    waitForEvent('canplaythrough', canplaythrough);
+}
+
+function testMode(uri)
+{
+    function seeked()
+    {
+        testExpected("textTrackDisplayElement(video, 'cue')", null);
+
+        consoleWrite("<br><i>** Showing a track should show active cues immediately<" + "/i>");
+        run("inbandTrack1.mode = 'showing'");
+
+        testExpected("textTrackDisplayElement(video, 'cue').textContent", null, '!=');
+        testExpected("inbandTrack1.activeCues.length", 1);
+
+        consoleWrite("");
+        endTest();
+    }
+
+    function canplaythrough()
+    {
+        run("inbandTrack1 = video.textTracks[0]");
+
+        consoleWrite("<br><i>** A hidden track should not have visible cues<" + "/i>");
+        run("inbandTrack1.mode = 'hidden'");
+        testExpected("inbandTrack1.activeCues.length", 0);
+
+        run("video.play()");
+        setTimeout(function() { video.pause(); video.currentTime = 0.5; }, 500);
+    }
+
+    findMediaElement();
+    video.src = uri;
+    waitForEvent('seeked', seeked);
+    waitForEvent('canplaythrough', canplaythrough);
+}
+
+function testStyle(uri)
+{
+    function seeked()
+    {
+        consoleWrite("<br><i>** Test current cue colors</i>");
+
+        run("cueDisplayElement = textTrackDisplayElement(video, 'display', 0)");
+        testExpected("getComputedStyle(cueDisplayElement).color", "rgb(255, 255, 255)");
+
+        run("cueNode = textTrackDisplayElement(video, 'cue')");
+        testExpected("getComputedStyle(cueNode).backgroundColor", "rgba(0, 0, 0, 0.8)");
+
+        endTest();
+    }
+
+    function canplaythrough()
+    {
+        consoleWrite("<br><i>** Setting track 1 to showing and starting video</i>");
+        run("inbandTrack1 = video.textTracks[0]");
+
+        inbandTrack1.mode = 'showing';
+        run("video.play()");
+        setTimeout(function() { video.pause(); video.currentTime = 0.3; }, 1500);
+    }
+
+    consoleWrite("Test that style is applied to all cues correctly.");
+    findMediaElement();
+    video.src = uri;
+    waitForEvent('seeked', seeked);
+    waitForEvent('canplaythrough', canplaythrough);
+}
+
+function testTrackOrder(uri) {
+    var addtrackEventCount = 0;
+
+    function trackAdded(event)
+    {
+        consoleWrite("EVENT(" + event.type + ")");
+        compareTracks("event.track", "video.textTracks[" + addtrackEventCount + "]");
+        ++addtrackEventCount;
+        consoleWrite("");
+    }
+
+    function compareTracks(track1, track2)
+    {
+        var equal = (eval(track1) == eval(track2));
+        reportExpected(equal, track1, "==", track2, track1);
+    }
+
+    function canplaythrough()
+    {
+        consoleWrite("<br><i>** Check initial in-band track states</i>");
+        testExpected("video.textTracks.length", 2);
+        run("inbandTrack1 = video.textTracks[0]");
+        run("inbandTrack2 = video.textTracks[1]");
+
+        consoleWrite("<br><i>** Add two tracks, check sort order<" + "/i>");
+        run("addTrack = video.addTextTrack('captions', 'Caption Track', 'en')");
+        run("trackElement = document.createElement('track')");
+        trackElement.label = '<track>';
+        run("video.appendChild(trackElement)");
+        testExpected("video.textTracks.length", 4);
+
+        compareTracks("video.textTracks[0]", "trackElement.track");
+        compareTracks("video.textTracks[1]", "addTrack");
+        compareTracks("video.textTracks[2]", "inbandTrack1");
+        compareTracks("video.textTracks[3]", "inbandTrack2");
+
+        consoleWrite("<br><i>** Unload video file, check track count<" + "/i>");
+        run("video.src = ''");
+        testExpected("video.textTracks.length", 2);
+
+        consoleWrite("");
+        endTest();
+    }
+
+    findMediaElement();
+    video.textTracks.addEventListener("addtrack", trackAdded);
+    video.src = uri;
+    waitForEvent('canplaythrough', canplaythrough);
+}
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once-expected.txt
new file mode 100644 (file)
index 0000000..63db5e7
--- /dev/null
@@ -0,0 +1,19 @@
+Check that we don't have duplicate cues after seeking backwards.
+
+EVENT(canplaythrough)
+
+** Setting track 1 to showing
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(inbandTrack1.mode = 'showing')
+RUN(video.play())
+EXPECTED (inbandTrack1.cues.length > '0') OK
+RUN(video.pause())
+RUN(video.currentTime = 0)
+RUN(video.play())
+
+EVENT(seeked)
+EXPECTED (inbandTrack1.cues.length > '0') OK
+RUN(video.pause())
+Test all cues are equal OK
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-cues-added-once.html
new file mode 100644 (file)
index 0000000..1896ff1
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testCuesAddedOnce('../../content/counting-subtitled-kate.ogv')">
+        <video controls></video>
+        <p>Check that we don't have duplicate cues after seeking backwards.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind-expected.txt
new file mode 100644 (file)
index 0000000..70b4a91
--- /dev/null
@@ -0,0 +1,11 @@
+Check in-band text tracks' kind attributes.
+
+EVENT(canplaythrough)
+
+** Check in-band kind attributes
+EXPECTED (video.textTracks.length == '2') OK
+EXPECTED (video.textTracks[0].kind == 'subtitles') OK
+EXPECTED (video.textTracks[1].kind == 'subtitles') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-kind.html
new file mode 100644 (file)
index 0000000..d26e0df
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testAttribute('../../content/counting-subtitled-kate.ogv', 'kind', ['subtitles', 'subtitles'])">
+        <video controls></video>
+        <p>Check in-band text tracks' kind attributes.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-language-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-language-expected.txt
new file mode 100644 (file)
index 0000000..8420351
--- /dev/null
@@ -0,0 +1,11 @@
+Check in-band text tracks' language attributes.
+
+EVENT(canplaythrough)
+
+** Check in-band kind attributes
+EXPECTED (video.textTracks.length == '2') OK
+EXPECTED (video.textTracks[0].language == 'en') OK
+EXPECTED (video.textTracks[1].language == 'fr') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-language.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-language.html
new file mode 100644 (file)
index 0000000..111995f
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testAttribute('../../content/counting-subtitled-kate.ogv', 'language', ['en', 'fr'])">
+        <video controls></video>
+        <p>Check in-band text tracks' language attributes.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode-expected.txt
new file mode 100644 (file)
index 0000000..2bb59e2
--- /dev/null
@@ -0,0 +1,19 @@
+Test that cues from in-band tracks are displayed immediately when a track is made visible.
+
+EVENT(canplaythrough)
+RUN(inbandTrack1 = video.textTracks[0])
+
+** A hidden track should not have visible cues
+RUN(inbandTrack1.mode = 'hidden')
+EXPECTED (inbandTrack1.activeCues.length == '0') OK
+RUN(video.play())
+EVENT(seeked)
+No text track cue with display id 'cue' is currently visible
+
+** Showing a track should show active cues immediately
+RUN(inbandTrack1.mode = 'showing')
+EXPECTED (textTrackDisplayElement(video, 'cue').textContent != 'null') OK
+EXPECTED (inbandTrack1.activeCues.length == '1') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-mode.html
new file mode 100644 (file)
index 0000000..e1def13
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>In-band track cues displayed immediately</title>
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../media-controls.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testMode('../../content/counting-subtitled-kate.ogv')">
+        <video controls></video>
+        <p>Test that cues from in-band tracks are displayed immediately when a track is made visible.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-style-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-style-expected.txt
new file mode 100644 (file)
index 0000000..1694848
--- /dev/null
@@ -0,0 +1,15 @@
+Test that style is applied to all cues correctly.
+EVENT(canplaythrough)
+
+** Setting track 1 to showing and starting video
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(video.play())
+EVENT(seeked)
+
+** Test current cue colors
+RUN(cueDisplayElement = textTrackDisplayElement(video, 'display', 0))
+EXPECTED (getComputedStyle(cueDisplayElement).color == 'rgb(255, 255, 255)') OK
+RUN(cueNode = textTrackDisplayElement(video, 'cue'))
+EXPECTED (getComputedStyle(cueNode).backgroundColor == 'rgba(0, 0, 0, 0.8)') OK
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-style.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-style.html
new file mode 100644 (file)
index 0000000..c7c54f8
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../media-controls.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testStyle('../../content/counting-subtitled-kate.ogv')">
+        <video controls >
+        </video>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order-expected.txt b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order-expected.txt
new file mode 100644 (file)
index 0000000..de9041e
--- /dev/null
@@ -0,0 +1,31 @@
+Test track order when using in-band and out-of-band text tracks.
+
+EVENT(addtrack)
+EXPECTED (event.track == 'video.textTracks[0]') OK
+
+EVENT(addtrack)
+EXPECTED (event.track == 'video.textTracks[1]') OK
+
+EVENT(canplaythrough)
+
+** Check initial in-band track states
+EXPECTED (video.textTracks.length == '2') OK
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(inbandTrack2 = video.textTracks[1])
+
+** Add two tracks, check sort order
+RUN(addTrack = video.addTextTrack('captions', 'Caption Track', 'en'))
+RUN(trackElement = document.createElement('track'))
+RUN(video.appendChild(trackElement))
+EXPECTED (video.textTracks.length == '4') OK
+EXPECTED (video.textTracks[0] == 'trackElement.track') OK
+EXPECTED (video.textTracks[1] == 'addTrack') OK
+EXPECTED (video.textTracks[2] == 'inbandTrack1') OK
+EXPECTED (video.textTracks[3] == 'inbandTrack2') OK
+
+** Unload video file, check track count
+RUN(video.src = '')
+EXPECTED (video.textTracks.length == '2') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order.html b/LayoutTests/media/track/in-band/track-in-band-kate-ogg-track-order.html
new file mode 100644 (file)
index 0000000..4108a6e
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testTrackOrder('../../content/counting-subtitled-kate.ogv')">
+        <video controls></video>
+        <p>Test track order when using in-band and out-of-band text tracks.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once-expected.txt
new file mode 100644 (file)
index 0000000..63db5e7
--- /dev/null
@@ -0,0 +1,19 @@
+Check that we don't have duplicate cues after seeking backwards.
+
+EVENT(canplaythrough)
+
+** Setting track 1 to showing
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(inbandTrack1.mode = 'showing')
+RUN(video.play())
+EXPECTED (inbandTrack1.cues.length > '0') OK
+RUN(video.pause())
+RUN(video.currentTime = 0)
+RUN(video.play())
+
+EVENT(seeked)
+EXPECTED (inbandTrack1.cues.length > '0') OK
+RUN(video.pause())
+Test all cues are equal OK
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-cues-added-once.html
new file mode 100644 (file)
index 0000000..3f3b74c
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testCuesAddedOnce('../../content/counting-subtitled-srt.mkv')">
+        <video controls></video>
+        <p>Check that we don't have duplicate cues after seeking backwards.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind-expected.txt
new file mode 100644 (file)
index 0000000..70b4a91
--- /dev/null
@@ -0,0 +1,11 @@
+Check in-band text tracks' kind attributes.
+
+EVENT(canplaythrough)
+
+** Check in-band kind attributes
+EXPECTED (video.textTracks.length == '2') OK
+EXPECTED (video.textTracks[0].kind == 'subtitles') OK
+EXPECTED (video.textTracks[1].kind == 'subtitles') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-kind.html
new file mode 100644 (file)
index 0000000..e47a7bb
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testAttribute('../../content/counting-subtitled-srt.mkv', 'kind', ['subtitles', 'subtitles'])">
+        <video controls></video>
+        <p>Check in-band text tracks' kind attributes.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-language-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-language-expected.txt
new file mode 100644 (file)
index 0000000..8420351
--- /dev/null
@@ -0,0 +1,11 @@
+Check in-band text tracks' language attributes.
+
+EVENT(canplaythrough)
+
+** Check in-band kind attributes
+EXPECTED (video.textTracks.length == '2') OK
+EXPECTED (video.textTracks[0].language == 'en') OK
+EXPECTED (video.textTracks[1].language == 'fr') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-language.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-language.html
new file mode 100644 (file)
index 0000000..def65be
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testAttribute('../../content/counting-subtitled-srt.mkv', 'language', ['en', 'fr'])">
+        <video controls></video>
+        <p>Check in-band text tracks' language attributes.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode-expected.txt
new file mode 100644 (file)
index 0000000..2bb59e2
--- /dev/null
@@ -0,0 +1,19 @@
+Test that cues from in-band tracks are displayed immediately when a track is made visible.
+
+EVENT(canplaythrough)
+RUN(inbandTrack1 = video.textTracks[0])
+
+** A hidden track should not have visible cues
+RUN(inbandTrack1.mode = 'hidden')
+EXPECTED (inbandTrack1.activeCues.length == '0') OK
+RUN(video.play())
+EVENT(seeked)
+No text track cue with display id 'cue' is currently visible
+
+** Showing a track should show active cues immediately
+RUN(inbandTrack1.mode = 'showing')
+EXPECTED (textTrackDisplayElement(video, 'cue').textContent != 'null') OK
+EXPECTED (inbandTrack1.activeCues.length == '1') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-mode.html
new file mode 100644 (file)
index 0000000..3652ec0
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>In-band track cues displayed immediately</title>
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../media-controls.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testMode('../../content/counting-subtitled-srt.mkv')">
+        <video controls></video>
+        <p>Test that cues from in-band tracks are displayed immediately when a track is made visible.</p>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-style-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-style-expected.txt
new file mode 100644 (file)
index 0000000..1694848
--- /dev/null
@@ -0,0 +1,15 @@
+Test that style is applied to all cues correctly.
+EVENT(canplaythrough)
+
+** Setting track 1 to showing and starting video
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(video.play())
+EVENT(seeked)
+
+** Test current cue colors
+RUN(cueDisplayElement = textTrackDisplayElement(video, 'display', 0))
+EXPECTED (getComputedStyle(cueDisplayElement).color == 'rgb(255, 255, 255)') OK
+RUN(cueNode = textTrackDisplayElement(video, 'cue'))
+EXPECTED (getComputedStyle(cueNode).backgroundColor == 'rgba(0, 0, 0, 0.8)') OK
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-style.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-style.html
new file mode 100644 (file)
index 0000000..790da12
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../media-controls.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testStyle('../../content/counting-subtitled-srt.mkv')">
+        <video controls >
+        </video>
+    </body>
+</html>
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order-expected.txt b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order-expected.txt
new file mode 100644 (file)
index 0000000..de9041e
--- /dev/null
@@ -0,0 +1,31 @@
+Test track order when using in-band and out-of-band text tracks.
+
+EVENT(addtrack)
+EXPECTED (event.track == 'video.textTracks[0]') OK
+
+EVENT(addtrack)
+EXPECTED (event.track == 'video.textTracks[1]') OK
+
+EVENT(canplaythrough)
+
+** Check initial in-band track states
+EXPECTED (video.textTracks.length == '2') OK
+RUN(inbandTrack1 = video.textTracks[0])
+RUN(inbandTrack2 = video.textTracks[1])
+
+** Add two tracks, check sort order
+RUN(addTrack = video.addTextTrack('captions', 'Caption Track', 'en'))
+RUN(trackElement = document.createElement('track'))
+RUN(video.appendChild(trackElement))
+EXPECTED (video.textTracks.length == '4') OK
+EXPECTED (video.textTracks[0] == 'trackElement.track') OK
+EXPECTED (video.textTracks[1] == 'addTrack') OK
+EXPECTED (video.textTracks[2] == 'inbandTrack1') OK
+EXPECTED (video.textTracks[3] == 'inbandTrack2') OK
+
+** Unload video file, check track count
+RUN(video.src = '')
+EXPECTED (video.textTracks.length == '2') OK
+
+END OF TEST
+
diff --git a/LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order.html b/LayoutTests/media/track/in-band/track-in-band-srt-mkv-track-order.html
new file mode 100644 (file)
index 0000000..8b0de8b
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+        <script src=../../media-file.js></script>
+        <script src=../../video-test.js></script>
+        <script src=../../in-band-cues.js></script>
+    </head>
+    <body onload="testTrackOrder('../../content/counting-subtitled-srt.mkv')">
+        <video controls></video>
+        <p>Test track order when using in-band and out-of-band text tracks.</p>
+    </body>
+</html>
index b8f1981058ee990d70642df9294ce1959391517c..6113066a82768b8ee88eb9b731d70d2caf8403b7 100644 (file)
@@ -1300,3 +1300,6 @@ webkit.org/b/120087 [ Lion ] fast/forms/submit-to-url-fragment.html [ Pass Crash
 webkit.org/b/117962 [ Lion ] media/video-played-collapse.html [ Failure Pass ]
 
 webkit.org/b/120387 svg/animations/svglengthlist-animation-3.html [ Pass Failure ]
+
+# Don't run ogv and mkv tests on mac
+media/track/in-band [ WontFix ]
index cddb2303ea63af90bbc0d60cc6b891699fd83a99..e94b7425370f69329aabfcf0956e34433d9d755f 100644 (file)
@@ -2710,7 +2710,9 @@ if (ENABLE_VIDEO_TRACK)
     list(APPEND WebCore_SOURCES
         html/track/AudioTrack.cpp
         html/track/AudioTrackList.cpp
+        html/track/InbandGenericTextTrack.cpp
         html/track/InbandTextTrack.cpp
+        html/track/InbandWebVTTTextTrack.cpp
         html/track/LoadableTextTrack.cpp
         html/track/TextTrack.cpp
         html/track/TextTrackCue.cpp
index 06e8d4e8b7de6bcf1be18dff26278e46a0b1b4db..5f04ceff1fb17399802a9da436bdfa8ba9e169b5 100644 (file)
@@ -1,3 +1,122 @@
+2013-08-30  Brendan Long  <b.long@cablelabs.com>
+
+        [GStreamer] support in-band text tracks
+        https://bugs.webkit.org/show_bug.cgi?id=103771
+
+        Reviewed by Eric Carlson.
+
+        Tests: New tests added because existing tests were too specific.
+           media/track/in-band/track-in-band-kate-ogg-cues-added-once.html
+           media/track/in-band/track-in-band-kate-ogg-kind.html
+           media/track/in-band/track-in-band-kate-ogg-language.html
+           media/track/in-band/track-in-band-kate-ogg-mode.html
+           media/track/in-band/track-in-band-kate-ogg-style.html
+           media/track/in-band/track-in-band-kate-ogg-track-order.html
+           media/track/in-band/track-in-band-srt-mkv-cues-added-once.html
+           media/track/in-band/track-in-band-srt-mkv-kind.html
+           media/track/in-band/track-in-band-srt-mkv-language.html
+           media/track/in-band/track-in-band-srt-mkv-mode.html
+           media/track/in-band/track-in-band-srt-mkv-style.html
+           media/track/in-band/track-in-band-srt-mkv-track-order.html
+
+        * CMakeLists.txt: Add InbandTextTrackPrivateGStreamer, InbandGenericTextTrack, InbandWebVTTTextTrack, and TextCombinerGStreamer files.
+        * GNUmakefile.list.am: Same.
+        * PlatformEfl.cmake: Same.
+        * Target.pri: Same.
+        * WebCore.vcxproj/WebCore.vcxproj: Same.
+        * WebCore.vcxproj/WebCore.vcxproj.filters: Same.
+        * WebCore.xcodeproj/project.pbxproj: Same.
+        * html/track/InbandGenericTextTrack.cpp: Split out code for handling generic cues.
+        (WebCore::GenericTextTrackCueMap::GenericTextTrackCueMap): Move from InbandTextTrack.
+        (WebCore::GenericTextTrackCueMap::~GenericTextTrackCueMap): Same.
+        (WebCore::GenericTextTrackCueMap::add): Same.
+        (WebCore::GenericTextTrackCueMap::find): Same.
+        (WebCore::GenericTextTrackCueMap::remove): Same.
+        (WebCore::InbandGenericTextTrack::create): Same.
+        (WebCore::InbandGenericTextTrack::updateCueFromCueData): Same.
+        (WebCore::InbandGenericTextTrack::addGenericCue): Same.
+        (WebCore::InbandGenericTextTrack::updateGenericCue): Same.
+        (WebCore::InbandGenericTextTrack::removeGenericCue): Same.
+        (WebCore::InbandGenericTextTrack::removeCue): Same.
+        (WebCore::InbandGenericTextTrack::InbandGenericTextTrack): Empty.
+        (WebCore::InbandGenericTextTrack::~InbandGenericTextTrack): Empty.
+        * html/track/InbandGenericTextTrack.h: Copied from Source/WebCore/html/track/InbandTextTrack.h.
+        The only addition is the ASSERT_NOT_REACHED() for WebVTT cues.
+        * html/track/InbandTextTrack.cpp: Add label and language changed callbacks.
+        (WebCore::InbandTextTrack::create): Return a generic or WebVTT text track based on the private CueFormat.
+        (WebCore::InbandTextTrack::labelChanged): Added.
+        (WebCore::InbandTextTrack::languageChanged): Added.
+        * html/track/InbandTextTrack.h: Add label and language changed callbacks.
+        * html/track/InbandWebVTTTextTrack.cpp: Added, based on InbandTextTrack.
+        (WebCore::InbandWebVTTTextTrack::create): Same.
+        (WebCore::InbandWebVTTTextTrack::InbandWebVTTTextTrack): Empty.
+        (WebCore::InbandWebVTTTextTrack::~InbandWebVTTTextTrack): Empty.
+        (WebCore::InbandWebVTTTextTrack::parseWebVTTCueData): Sends data to a WebVTTParser.
+        (WebCore::InbandWebVTTTextTrack::newCuesParsed): Adds cues when WebVTTParser parses them.
+        (WebCore::InbandWebVTTTextTrack::fileFailedToParse): Prints a warning when WebVTTParser has a problem.
+        * html/track/InbandWebVTTTextTrack.h: Added.
+        * platform/graphics/InbandTextTrackPrivate.h:
+        (WebCore::InbandTextTrackPrivate::cueFormat): For determining if the track will have generic or WebVTT cues.
+        (WebCore::InbandTextTrackPrivate::InbandTextTrackPrivate): Pass CueFormat in the constructor.
+        * platform/graphics/InbandTextTrackPrivateClient.h: Same.
+        * platform/graphics/avfoundation/InbandTextTrackPrivateAVF.cpp:
+        (WebCore::InbandTextTrackPrivateAVF::InbandTextTrackPrivateAVF): Pass CueFormat (Generic) to InbandTextTrackPrivate.
+        * platform/graphics/gstreamer/GRefPtrGStreamer.cpp: Add GRefPtr specializations for GstSample and GstEvent.
+        * platform/graphics/gstreamer/GRefPtrGStreamer.h: Same.
+        * platform/graphics/gstreamer/GStreamerUtilities.h: Add WARN_MEDIA_MESSAGE.
+        * platform/graphics/gstreamer/GStreamerVersioning.h: Add a function to check GStreamer version at runtime.
+        * platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp: Added.
+        (WebCore::textTrackPrivateEventCallback): Watches for tag and stream start events.
+        (WebCore::textTrackPrivateSampleTimeoutCallback): See notifyTrackOfSample();
+        (WebCore::textTrackPrivateStreamTimeoutCallback): See notifyTrackOfStreamChanged();
+        (WebCore::textTrackPrivateTagsChangeTimeoutCallback): See notifyTrackOfTagsChanged();
+        (WebCore::InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer): Initializes tags and stream and sets up event callback.
+        (WebCore::InbandTextTrackPrivateGStreamer::~InbandTextTrackPrivateGStreamer): Calls disconnect:
+        (WebCore::InbandTextTrackPrivateGStreamer::disconnect): Removes signal handlers and frees some memory.
+        (WebCore::InbandTextTrackPrivateGStreamer::handleSample): Adds samples to a list and sets up callback.
+        (WebCore::InbandTextTrackPrivateGStreamer::streamChanged): Sets up callback.
+        (WebCore::InbandTextTrackPrivateGStreamer::tagsChanged): Same.
+        (WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfSample): Parses all queued samples with WebVTTParser.
+        (WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfStreamChanged): Keeps track of current stream.
+        (WebCore::InbandTextTrackPrivateGStreamer::notifyTrackOfTagsChanged): Sets label and language from tags.
+        * platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h: Added.
+        (WebCore::InbandTextTrackPrivateGStreamer::create): Basic RefPtr create function.
+        (WebCore::InbandTextTrackPrivateGStreamer::pad): Returns the pad this track is associated with (used
+        to determine if a playbin text stream has already been associated with a text track).
+        (WebCore::InbandTextTrackPrivateGStreamer::setIndex): Sets the track index (used for sorting).
+        (WebCore::InbandTextTrackPrivateGStreamer::streamId): Returns the stream ID (used to handle new samples).
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::mediaPlayerPrivateTextChangedCallback): Called for playbin "text-changed" event. See textChanged().
+        (WebCore::mediaPlayerPrivateTextChangeTimeoutCallback): See notifyPlayerOfText().
+        (WebCore::mediaPlayerPrivateNewTextSampleCallback): See newTextSample().
+        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer): Initialize m_textTimerHandler.
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer): Disconnect text tracks (they don't necessarily
+        get freed here, since a script could hold a reference).
+        (WebCore::MediaPlayerPrivateGStreamer::textChanged): Setup callback for notifyPlayerOfText.
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfText): Create text tracks.
+        (WebCore::MediaPlayerPrivateGStreamer::newTextSample): Handle new samples by giving them to a text track
+        with a matching stream. This method is syncryonous because we need to get the stream start sticky event
+        immediately.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+        * platform/graphics/gstreamer/TextCombinerGStreamer.cpp: Added. This element forwards buffers from all
+        of its input pads, but also converts plain text to WebVTT as needed.
+        (webkit_text_combiner_init): Setup internal funnel.
+        (webkitTextCombinerPadEvent): If the caps are plain text make sure we have a webvttenv, otherwise connect
+        directly to the funnel.
+        (webkitTextCombinerRequestNewPad): Setup ghostpad and event callback.
+        (webkitTextCombinerReleasePad): Release pad and optional associated webvttenc.
+        (webkit_text_combiner_class_init): Setup pad templates and request/release pad functions.
+        (webkitTextCombinerNew): Returns a new WebKitTextCombiner.
+        * platform/graphics/gstreamer/TextCombinerGStreamer.h: Added.
+        * platform/graphics/gstreamer/TextSinkGStreamer.cpp: Added.
+        (webkit_text_sink_init): Set sync=false.
+        (webkitTextSinkGetProperty): Ignore sync property.
+        (webkitTextSinkSetProperty): Same.
+        (webkitTextSinkQuery): Ignore position and duration queries, forward everything else to appsink.
+        (webkit_text_sink_class_init): Setup property and query functions.
+        (webkitTextSinkNew): Return a new WebKitTextSink.
+        * platform/graphics/gstreamer/TextSinkGStreamer.h: Added.
+
 2013-08-30  Dirk Schulze  <krit@webkit.org>
 
         Animate CSS Image filter() function
index 9d7b274baa482a5e8a88a75f8b9ffd17d3d077de..b7a8e542ddf0306bcb4f7842eca9fc4e5696d76e 100644 (file)
@@ -3725,8 +3725,12 @@ webcore_sources += \
        Source/WebCore/html/track/AudioTrack.h \
        Source/WebCore/html/track/AudioTrackList.cpp \
        Source/WebCore/html/track/AudioTrackList.h \
+       Source/WebCore/html/track/InbandGenericTextTrack.cpp \
+       Source/WebCore/html/track/InbandGenericTextTrack.h \
        Source/WebCore/html/track/InbandTextTrack.cpp \
        Source/WebCore/html/track/InbandTextTrack.h \
+       Source/WebCore/html/track/InbandWebVTTTextTrack.cpp \
+       Source/WebCore/html/track/InbandWebVTTTextTrack.h \
        Source/WebCore/html/track/LoadableTextTrack.cpp \
        Source/WebCore/html/track/LoadableTextTrack.h \
        Source/WebCore/html/track/TextTrack.cpp \
@@ -6327,7 +6331,14 @@ platform_sources += \
        Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp \
        Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.h \
        Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp \
-       Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h
+       Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h \
+       Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp \
+       Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.h \
+       Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.cpp \
+       Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.h
+webcore_platform_sources += \
+       Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp \
+       Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h
 endif
 
 # ---
index 20a88f6f72214fe3db32c50789eea178dea1aa11..2180c720995b33c3535086fb07108e4346927d7b 100644 (file)
@@ -123,9 +123,12 @@ list(APPEND WebCore_SOURCES
     platform/graphics/gstreamer/GStreamerUtilities.cpp
     platform/graphics/gstreamer/GStreamerVersioning.cpp
     platform/graphics/gstreamer/ImageGStreamerCairo.cpp
+    platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp
     platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp
     platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
     platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp
+    platform/graphics/gstreamer/TextCombinerGStreamer.cpp
+    platform/graphics/gstreamer/TextSinkGStreamer.cpp
     platform/graphics/gstreamer/VideoSinkGStreamer.cpp
     platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
 
index 27f83a6bb6da2ebc525ff434b284931d2b09058b..dd3dddd44c984bdd437ca7a1ffa1e3fec3e0eacf 100644 (file)
@@ -3333,6 +3333,16 @@ enable?(VIDEO) {
             platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp \
             platform/graphics/gstreamer/PlatformVideoWindowQt.cpp \
             platform/graphics/gstreamer/ImageGStreamerQt.cpp
+        enable?(VIDEO_TRACK) {
+            HEADERS += \
+                platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h \
+                platform/graphics/gstreamer/TextCombinerGStreamer.h \
+                platform/graphics/gstreamer/TextSinkGStreamer.h
+            SOURCES += \
+                platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp \
+                platform/graphics/gstreamer/TextCombinerGStreamer.cpp \
+                platform/graphics/gstreamer/TextSinkGStreamer.cpp
+        }
 
     } else:use?(QT_MULTIMEDIA) {
         HEADERS += \
@@ -3902,7 +3912,9 @@ enable?(VIDEO_TRACK) {
         html/HTMLTrackElement.h \
         html/track/AudioTrack.h \
         html/track/AudioTrackList.h \
+        html/track/InbandGenericTextTrack.h \
         html/track/InbandTextTrack.h \
+        html/track/InbandWebVTTTextTrack.h \
         html/track/LoadableTextTrack.h \
         html/track/TextTrack.h \
         html/track/TextTrackCue.h \
@@ -3936,7 +3948,9 @@ enable?(VIDEO_TRACK) {
         html/HTMLTrackElement.cpp \
         html/track/AudioTrack.cpp \
         html/track/AudioTrackList.cpp \
+        html/track/InbandGenericTextTrack.cpp \
         html/track/InbandTextTrack.cpp \
+        html/track/InbandWebVTTTextTrack.cpp \
         html/track/LoadableTextTrack.cpp \
         html/track/TextTrack.cpp \
         html/track/TextTrackCue.cpp \
index 2f9acd55b0e4a1859848f5227b0b6837d3ea2910..7f75169d79a3ac5ede642d19ef80877bc2b6188a 100644 (file)
     <ClCompile Include="..\html\shadow\SliderThumbElement.cpp" />
     <ClCompile Include="..\html\shadow\SpinButtonElement.cpp" />
     <ClCompile Include="..\html\shadow\TextControlInnerElements.cpp" />
+    <ClCompile Include="..\html\track\InbandGenericTextTrack.cpp" />
     <ClCompile Include="..\html\track\InbandTextTrack.cpp" />
+    <ClCompile Include="..\html\track\InbandWebVTTTextTrack.cpp" />
     <ClCompile Include="..\html\track\LoadableTextTrack.cpp" />
     <ClCompile Include="..\html\track\TextTrack.cpp" />
     <ClCompile Include="..\html\track\TextTrackCue.cpp" />
     <ClInclude Include="..\html\shadow\SliderThumbElement.h" />
     <ClInclude Include="..\html\shadow\SpinButtonElement.h" />
     <ClInclude Include="..\html\shadow\TextControlInnerElements.h" />
+    <ClInclude Include="..\html\track\InbandGenericTextTrack.h" />
     <ClInclude Include="..\html\track\InbandTextTrack.h" />
+    <ClInclude Include="..\html\track\InbandWebVTTTextTrack.h" />
     <ClInclude Include="..\html\track\LoadableTextTrack.h" />
     <ClInclude Include="..\html\track\TextTrack.h" />
     <ClInclude Include="..\html\track\TextTrackCue.h" />
index 01b2edcdfee451f8e8ea38b0660272d54d7251a2..e13e2177a20a55dbe733e544909b78155eb30bed 100644 (file)
     <ClCompile Include="..\html\shadow\TextControlInnerElements.cpp">
       <Filter>html\shadow</Filter>
     </ClCompile>
+    <ClCompile Include="..\html\track\InbandGenericTextTrack.cpp">
+      <Filter>html\track</Filter>
+    </ClCompile>
     <ClCompile Include="..\html\track\InbandTextTrack.cpp">
       <Filter>html\track</Filter>
     </ClCompile>
+    <ClCompile Include="..\html\track\InbandWebVTTTextTrack.cpp">
+      <Filter>html\track</Filter>
+    </ClCompile>
     <ClCompile Include="..\html\track\LoadableTextTrack.cpp">
       <Filter>html\track</Filter>
     </ClCompile>
     <ClInclude Include="..\html\shadow\TextControlInnerElements.h">
       <Filter>html\shadow</Filter>
     </ClInclude>
+    <ClInclude Include="..\html\track\InbandGenericTextTrack.h">
+      <Filter>html\track</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\track\InbandTextTrack.h">
       <Filter>html\track</Filter>
     </ClInclude>
+    <ClInclude Include="..\html\track\InbandWebVTTTextTrack.h">
+      <Filter>html\track</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\track\LoadableTextTrack.h">
       <Filter>html\track</Filter>
     </ClInclude>
index 527e84be50ba7a61539d472bbc6ceb30149bc81f..d5dbbe84d9c702b87589b1b5cdadae5e8edd8c73 100644 (file)
                BCFE2F120C1B58380020235F /* JSRect.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFE2F100C1B58370020235F /* JSRect.h */; };
                BCFF64910EAD15C200C1D6F7 /* LengthBox.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFF648F0EAD15C200C1D6F7 /* LengthBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BCFF64920EAD15C200C1D6F7 /* LengthSize.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFF64900EAD15C200C1D6F7 /* LengthSize.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               BE16C59217CFE17200852C04 /* InbandGenericTextTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE16C58E17CFE17200852C04 /* InbandGenericTextTrack.cpp */; };
+               BE16C59317CFE17200852C04 /* InbandGenericTextTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = BE16C58F17CFE17200852C04 /* InbandGenericTextTrack.h */; };
+               BE16C59417CFE17200852C04 /* InbandWebVTTTextTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE16C59017CFE17200852C04 /* InbandWebVTTTextTrack.cpp */; };
+               BE16C59517CFE17200852C04 /* InbandWebVTTTextTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = BE16C59117CFE17200852C04 /* InbandWebVTTTextTrack.h */; };
                BE6DF70B171CA2C500DD52B8 /* JSVideoTrackCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE6DF708171CA2C500DD52B8 /* JSVideoTrackCustom.cpp */; };
                BE6DF70D171CA2C500DD52B8 /* JSVideoTrackListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE6DF70A171CA2C500DD52B8 /* JSVideoTrackListCustom.cpp */; };
                BE6DF711171CA2DA00DD52B8 /* JSAudioTrackCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE6DF70E171CA2DA00DD52B8 /* JSAudioTrackCustom.cpp */; };
                BCFE2F100C1B58370020235F /* JSRect.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSRect.h; sourceTree = "<group>"; };
                BCFF648F0EAD15C200C1D6F7 /* LengthBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LengthBox.h; sourceTree = "<group>"; };
                BCFF64900EAD15C200C1D6F7 /* LengthSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LengthSize.h; sourceTree = "<group>"; };
+               BE16C58E17CFE17200852C04 /* InbandGenericTextTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InbandGenericTextTrack.cpp; sourceTree = "<group>"; };
+               BE16C58F17CFE17200852C04 /* InbandGenericTextTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandGenericTextTrack.h; sourceTree = "<group>"; };
+               BE16C59017CFE17200852C04 /* InbandWebVTTTextTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InbandWebVTTTextTrack.cpp; sourceTree = "<group>"; };
+               BE16C59117CFE17200852C04 /* InbandWebVTTTextTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandWebVTTTextTrack.h; sourceTree = "<group>"; };
                BE6DF708171CA2C500DD52B8 /* JSVideoTrackCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSVideoTrackCustom.cpp; sourceTree = "<group>"; };
                BE6DF70A171CA2C500DD52B8 /* JSVideoTrackListCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSVideoTrackListCustom.cpp; sourceTree = "<group>"; };
                BE6DF70E171CA2DA00DD52B8 /* JSAudioTrackCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAudioTrackCustom.cpp; sourceTree = "<group>"; };
                                BE88E0CF1715D2A200658D98 /* AudioTrackList.cpp */,
                                BE88E0D01715D2A200658D98 /* AudioTrackList.h */,
                                BE88E0D11715D2A200658D98 /* AudioTrackList.idl */,
+                               BE16C58E17CFE17200852C04 /* InbandGenericTextTrack.cpp */,
+                               BE16C58F17CFE17200852C04 /* InbandGenericTextTrack.h */,
                                0794178F166E855F009416C2 /* InbandTextTrack.cpp */,
                                07941790166E855F009416C2 /* InbandTextTrack.h */,
+                               BE16C59017CFE17200852C04 /* InbandWebVTTTextTrack.cpp */,
+                               BE16C59117CFE17200852C04 /* InbandWebVTTTextTrack.h */,
                                9759E93414EF1CF80026A2DD /* LoadableTextTrack.cpp */,
                                9759E94814EF1D490026A2DD /* LoadableTextTrack.h */,
                                9759E93514EF1CF80026A2DD /* TextTrack.cpp */,
                                FD1762E0176686D900D836A8 /* UpSampler.h in Headers */,
                                FD1762E4176686EA00D836A8 /* DownSampler.h in Headers */,
                                FBB0C5B817BBD629003D3677 /* CSSFilterImageValue.h in Headers */,
+                               BE16C59317CFE17200852C04 /* InbandGenericTextTrack.h in Headers */,
+                               BE16C59517CFE17200852C04 /* InbandWebVTTTextTrack.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                FD1762E3176686EA00D836A8 /* DownSampler.cpp in Sources */,
                                6E84E9E017668BEE00815B68 /* RasterShape.cpp in Sources */,
                                FBB0C5B717BBD626003D3677 /* CSSFilterImageValue.cpp in Sources */,
+                               BE16C59217CFE17200852C04 /* InbandGenericTextTrack.cpp in Sources */,
+                               BE16C59417CFE17200852C04 /* InbandWebVTTTextTrack.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 3d2b95f1235c8409061a9e381795e26f1404675f..04c05e0dda7fdf0d448ce80e1356e3cb55d63e73 100644 (file)
 #include "AudioTrackPrivate.h"
 #include "CaptionUserPreferences.h"
 #include "HTMLTrackElement.h"
+#include "InbandGenericTextTrack.h"
 #include "InbandTextTrack.h"
 #include "InbandTextTrackPrivate.h"
+#include "InbandWebVTTTextTrack.h"
 #include "RuntimeEnabledFeatures.h"
 #include "TextTrackCueList.h"
 #include "TextTrackList.h"
diff --git a/Source/WebCore/html/track/InbandGenericTextTrack.cpp b/Source/WebCore/html/track/InbandGenericTextTrack.cpp
new file mode 100644 (file)
index 0000000..f10c770
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "InbandGenericTextTrack.h"
+
+#include "ExceptionCodePlaceholder.h"
+#include "HTMLMediaElement.h"
+#include "InbandTextTrackPrivate.h"
+#include "Logging.h"
+#include "TextTrackCueGeneric.h"
+#include <math.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+GenericTextTrackCueMap::GenericTextTrackCueMap()
+{
+}
+
+GenericTextTrackCueMap::~GenericTextTrackCueMap()
+{
+}
+
+void GenericTextTrackCueMap::add(GenericCueData* cueData, TextTrackCueGeneric* cue)
+{
+    m_dataToCueMap.add(cueData, cue);
+    m_cueToDataMap.add(cue, cueData);
+}
+
+PassRefPtr<TextTrackCueGeneric> GenericTextTrackCueMap::find(GenericCueData* cueData)
+{
+    CueDataToCueMap::iterator iter = m_dataToCueMap.find(cueData);
+    if (iter == m_dataToCueMap.end())
+        return 0;
+
+    return iter->value;
+}
+
+PassRefPtr<GenericCueData> GenericTextTrackCueMap::find(TextTrackCue* cue)
+{
+    CueToDataMap::iterator iter = m_cueToDataMap.find(cue);
+    if (iter == m_cueToDataMap.end())
+        return 0;
+
+    return iter->value;
+}
+
+void GenericTextTrackCueMap::remove(GenericCueData* cueData)
+{
+    RefPtr<TextTrackCueGeneric> cue = find(cueData);
+
+    if (cue)
+        m_cueToDataMap.remove(cue);
+    m_dataToCueMap.remove(cueData);
+}
+
+void GenericTextTrackCueMap::remove(TextTrackCue* cue)
+{
+    RefPtr<GenericCueData> genericData = find(cue);
+    if (genericData) {
+        m_dataToCueMap.remove(genericData);
+        m_cueToDataMap.remove(cue);
+    }
+}
+
+PassRefPtr<InbandGenericTextTrack> InbandGenericTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
+{
+    return adoptRef(new InbandGenericTextTrack(context, client, playerPrivate));
+}
+
+InbandGenericTextTrack::InbandGenericTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
+    : InbandTextTrack(context, client, trackPrivate)
+{
+}
+
+InbandGenericTextTrack::~InbandGenericTextTrack()
+{
+}
+
+void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric* cue, GenericCueData* cueData)
+{
+    cue->willChange();
+
+    cue->setStartTime(cueData->startTime(), IGNORE_EXCEPTION);
+    double endTime = cueData->endTime();
+    if (std::isinf(endTime) && mediaElement())
+        endTime = mediaElement()->duration();
+    cue->setEndTime(endTime, IGNORE_EXCEPTION);
+    cue->setText(cueData->content());
+    cue->setId(cueData->id());
+    cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
+    cue->setFontSizeMultiplier(cueData->relativeFontSize());
+    cue->setFontName(cueData->fontName());
+
+    if (cueData->position() > 0)
+        cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
+    if (cueData->line() > 0)
+        cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
+    if (cueData->size() > 0)
+        cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
+    if (cueData->backgroundColor().isValid())
+        cue->setBackgroundColor(cueData->backgroundColor().rgb());
+    if (cueData->foregroundColor().isValid())
+        cue->setForegroundColor(cueData->foregroundColor().rgb());
+    if (cueData->highlightColor().isValid())
+        cue->setHighlightColor(cueData->highlightColor().rgb());
+
+    if (cueData->align() == GenericCueData::Start)
+        cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
+    else if (cueData->align() == GenericCueData::Middle)
+        cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
+    else if (cueData->align() == GenericCueData::End)
+        cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
+    cue->setSnapToLines(false);
+
+    cue->didChange();
+}
+
+void InbandGenericTextTrack::addGenericCue(InbandTextTrackPrivate* trackPrivate, PassRefPtr<GenericCueData> prpCueData)
+{
+    ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
+
+    RefPtr<GenericCueData> cueData = prpCueData;
+    if (m_cueMap.find(cueData.get()))
+        return;
+
+    RefPtr<TextTrackCueGeneric> cue = TextTrackCueGeneric::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
+    updateCueFromCueData(cue.get(), cueData.get());
+    if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
+        LOG(Media, "InbandGenericTextTrack::addGenericCue ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+        return;
+    }
+
+    if (cueData->status() != GenericCueData::Complete)
+        m_cueMap.add(cueData.get(), cue.get());
+
+    addCue(cue);
+}
+
+void InbandGenericTextTrack::updateGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
+{
+    RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
+    if (!cue)
+        return;
+
+    updateCueFromCueData(cue.get(), cueData);
+
+    if (cueData->status() == GenericCueData::Complete)
+        m_cueMap.remove(cueData);
+}
+
+void InbandGenericTextTrack::removeGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
+{
+    RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
+    if (cue) {
+        LOG(Media, "InbandGenericTextTrack::removeGenericCue removing cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+        removeCue(cue.get(), IGNORE_EXCEPTION);
+    } else
+        m_cueMap.remove(cueData);
+}
+
+void InbandGenericTextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
+{
+    m_cueMap.remove(cue);
+    TextTrack::removeCue(cue, ec);
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/InbandGenericTextTrack.h b/Source/WebCore/html/track/InbandGenericTextTrack.h
new file mode 100644 (file)
index 0000000..b2f1ab3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012, 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 InbandGenericTextTrack_h
+#define InbandGenericTextTrack_h
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "InbandTextTrack.h"
+#include "TextTrackCueGeneric.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Document;
+class InbandTextTrackPrivate;
+class TextTrackCue;
+
+class GenericTextTrackCueMap {
+public:
+    GenericTextTrackCueMap();
+    virtual ~GenericTextTrackCueMap();
+
+    void add(GenericCueData*, TextTrackCueGeneric*);
+
+    void remove(TextTrackCue*);
+    void remove(GenericCueData*);
+
+    PassRefPtr<GenericCueData> find(TextTrackCue*);
+    PassRefPtr<TextTrackCueGeneric> find(GenericCueData*);
+
+private:
+    typedef HashMap<RefPtr<TextTrackCue>, RefPtr<GenericCueData> > CueToDataMap;
+    typedef HashMap<RefPtr<GenericCueData>, RefPtr<TextTrackCueGeneric> > CueDataToCueMap;
+
+    CueToDataMap m_cueToDataMap;
+    CueDataToCueMap m_dataToCueMap;
+};
+
+class InbandGenericTextTrack : public InbandTextTrack {
+public:
+    static PassRefPtr<InbandGenericTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+    virtual ~InbandGenericTextTrack();
+
+private:
+    InbandGenericTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+
+    virtual void addGenericCue(InbandTextTrackPrivate*, PassRefPtr<GenericCueData>) OVERRIDE;
+    virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE;
+    virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE;
+    virtual void removeCue(TextTrackCue*, ExceptionCode&) OVERRIDE;
+
+    virtual void parseWebVTTCueData(InbandTextTrackPrivate*, const char*, unsigned) OVERRIDE { ASSERT_NOT_REACHED(); }
+
+    PassRefPtr<TextTrackCueGeneric> createCue(PassRefPtr<GenericCueData>);
+    void updateCueFromCueData(TextTrackCueGeneric*, GenericCueData*);
+
+    GenericTextTrackCueMap m_cueMap;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
index 0d5cf82a1c32a9178050a7a8b59424273dbd6e7c..ca1f89a08a5868b0725d3b8f05ca771dd63cad41 100644 (file)
@@ -33,7 +33,9 @@
 #include "Event.h"
 #include "ExceptionCodePlaceholder.h"
 #include "HTMLMediaElement.h"
+#include "InbandGenericTextTrack.h"
 #include "InbandTextTrackPrivate.h"
+#include "InbandWebVTTTextTrack.h"
 #include "Logging.h"
 #include "TextTrackCueGeneric.h"
 #include "TextTrackCueList.h"
 
 namespace WebCore {
 
-TextTrackCueMap::TextTrackCueMap()
-    : m_genericCueToDataMap(0)
-    , m_genericDataToCueMap(0)
-    , m_webVTTCueToDataMap(0)
-    , m_webVTTDataToCueMap(0)
+PassRefPtr<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext* context,
+    TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
 {
-}
-
-TextTrackCueMap::~TextTrackCueMap()
-{
-    if (m_genericCueToDataMap) {
-        delete m_genericCueToDataMap;
-        ASSERT(m_genericDataToCueMap);
-        delete m_genericDataToCueMap;
-    } else
-        ASSERT(!m_genericDataToCueMap);
-
-    if (m_webVTTCueToDataMap) {
-        delete m_webVTTCueToDataMap;
-        ASSERT(m_webVTTDataToCueMap);
-        delete m_webVTTDataToCueMap;
-    } else
-        ASSERT(!m_webVTTDataToCueMap);
-}
-
-void TextTrackCueMap::add(GenericCueData* cueData, TextTrackCueGeneric* cue)
-{
-    if (!m_genericDataToCueMap) {
-        m_genericDataToCueMap = new GenericCueDataToCueMap;
-        ASSERT(!m_genericCueToDataMap);
-        m_genericCueToDataMap = new GenericCueToDataMap;
-    } else
-        ASSERT(m_genericCueToDataMap);
-
-    m_genericDataToCueMap->add(cueData, cue);
-    m_genericCueToDataMap->add(cue, cueData);
-}
-
-void TextTrackCueMap::add(WebVTTCueData* cueData, TextTrackCue* cue)
-{
-    if (!m_webVTTDataToCueMap) {
-        m_webVTTDataToCueMap = new WebVTTCueDataToCueMap;
-        ASSERT(!m_webVTTCueToDataMap);
-        m_webVTTCueToDataMap = new WebVTTCueToDataMap;
-    } else
-        ASSERT(m_webVTTCueToDataMap);
-
-    m_webVTTDataToCueMap->add(cueData, cue);
-    m_webVTTCueToDataMap->add(cue, cueData);
-}
-
-PassRefPtr<TextTrackCueGeneric> TextTrackCueMap::find(GenericCueData* cueData)
-{
-    if (!m_genericDataToCueMap)
-        return 0;
-
-    GenericCueDataToCueMap::iterator iter = m_genericDataToCueMap->find(cueData);
-    if (iter == m_genericDataToCueMap->end())
-        return 0;
-
-    return iter->value;
-}
-
-PassRefPtr<TextTrackCue> TextTrackCueMap::find(WebVTTCueData* cueData)
-{
-    if (!m_webVTTDataToCueMap)
-        return 0;
-
-    WebVTTCueDataToCueMap::iterator iter = m_webVTTDataToCueMap->find(cueData);
-    if (iter == m_webVTTDataToCueMap->end())
-        return 0;
-
-    return iter->value;
-}
-
-PassRefPtr<GenericCueData> TextTrackCueMap::findGenericData(TextTrackCue* cue)
-{
-    if (!m_genericCueToDataMap)
-        return 0;
-
-    GenericCueToDataMap::iterator iter = m_genericCueToDataMap->find(cue);
-    if (iter == m_genericCueToDataMap->end())
-        return 0;
-
-    return iter->value;
-}
-
-PassRefPtr<WebVTTCueData> TextTrackCueMap::findWebVTTData(TextTrackCue* cue)
-{
-    if (!m_webVTTCueToDataMap)
-        return 0;
-
-    WebVTTCueToDataMap::iterator iter = m_webVTTCueToDataMap->find(cue);
-    if (iter == m_webVTTCueToDataMap->end())
+    switch (trackPrivate->cueFormat()) {
+    case InbandTextTrackPrivate::Generic:
+        return InbandGenericTextTrack::create(context, client, trackPrivate);
+    case InbandTextTrackPrivate::WebVTT:
+        return InbandWebVTTTextTrack::create(context, client, trackPrivate);
+    default:
+        ASSERT_NOT_REACHED();
         return 0;
-    
-    return iter->value;
-}
-
-void TextTrackCueMap::remove(GenericCueData* cueData)
-{
-    if (!m_genericCueToDataMap)
-        return;
-
-    RefPtr<TextTrackCueGeneric> cue = find(cueData);
-
-    if (cue)
-        m_genericCueToDataMap->remove(cue);
-    m_genericDataToCueMap->remove(cueData);
-}
-
-void TextTrackCueMap::remove(TextTrackCue* cue)
-{
-    if (m_genericCueToDataMap) {
-        RefPtr<GenericCueData> genericData = findGenericData(cue);
-        if (genericData) {
-            m_genericDataToCueMap->remove(genericData);
-            m_genericCueToDataMap->remove(cue);
-            return;
-        }
-    }
-
-    if (m_webVTTCueToDataMap) {
-        RefPtr<WebVTTCueData> webVTTData = findWebVTTData(cue);
-        if (webVTTData) {
-            m_webVTTDataToCueMap->remove(webVTTData);
-            m_webVTTCueToDataMap->remove(cue);
-        }
     }
 }
 
-void TextTrackCueMap::remove(WebVTTCueData* cueData)
-{
-    if (!m_webVTTCueToDataMap)
-        return;
-
-    RefPtr<TextTrackCue> cue = find(cueData);
-
-    if (cue)
-        m_webVTTCueToDataMap->remove(cue);
-    m_webVTTDataToCueMap->remove(cueData);
-}
-
-
-PassRefPtr<InbandTextTrack> InbandTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
-{
-    return adoptRef(new InbandTextTrack(context, client, playerPrivate));
-}
-
 InbandTextTrack::InbandTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> tracksPrivate)
     : TextTrack(context, client, emptyString(), tracksPrivate->label(), tracksPrivate->language(), InBand)
     , m_private(tracksPrivate)
@@ -289,118 +156,16 @@ size_t InbandTextTrack::inbandTrackIndex()
     return m_private->textTrackIndex();
 }
 
-void InbandTextTrack::updateCueFromCueData(TextTrackCueGeneric* cue, GenericCueData* cueData)
-{
-    cue->willChange();
-
-    cue->setStartTime(cueData->startTime(), IGNORE_EXCEPTION);
-    double endTime = cueData->endTime();
-    if (std::isinf(endTime) && mediaElement())
-        endTime = mediaElement()->duration();
-    cue->setEndTime(endTime, IGNORE_EXCEPTION);
-    cue->setText(cueData->content());
-    cue->setId(cueData->id());
-    cue->setBaseFontSizeRelativeToVideoHeight(cueData->baseFontSize());
-    cue->setFontSizeMultiplier(cueData->relativeFontSize());
-    cue->setFontName(cueData->fontName());
-
-    if (cueData->position() > 0)
-        cue->setPosition(lround(cueData->position()), IGNORE_EXCEPTION);
-    if (cueData->line() > 0)
-        cue->setLine(lround(cueData->line()), IGNORE_EXCEPTION);
-    if (cueData->size() > 0)
-        cue->setSize(lround(cueData->size()), IGNORE_EXCEPTION);
-    if (cueData->backgroundColor().isValid())
-        cue->setBackgroundColor(cueData->backgroundColor().rgb());
-    if (cueData->foregroundColor().isValid())
-        cue->setForegroundColor(cueData->foregroundColor().rgb());
-    if (cueData->highlightColor().isValid())
-        cue->setHighlightColor(cueData->highlightColor().rgb());
-
-    if (cueData->align() == GenericCueData::Start)
-        cue->setAlign(ASCIILiteral("start"), IGNORE_EXCEPTION);
-    else if (cueData->align() == GenericCueData::Middle)
-        cue->setAlign(ASCIILiteral("middle"), IGNORE_EXCEPTION);
-    else if (cueData->align() == GenericCueData::End)
-        cue->setAlign(ASCIILiteral("end"), IGNORE_EXCEPTION);
-    cue->setSnapToLines(false);
-
-    cue->didChange();
-}
-    
-void InbandTextTrack::addGenericCue(InbandTextTrackPrivate* trackPrivate, PassRefPtr<GenericCueData> prpCueData)
+void InbandTextTrack::labelChanged(InbandTextTrackPrivate* trackPrivate, const String& label)
 {
     ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
-
-    RefPtr<GenericCueData> cueData = prpCueData;
-    if (m_cueMap.find(cueData.get()))
-        return;
-
-    RefPtr<TextTrackCueGeneric> cue = TextTrackCueGeneric::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
-    updateCueFromCueData(cue.get(), cueData.get());
-    if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
-        LOG(Media, "InbandTextTrack::addGenericCue ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
-        return;
-    }
-
-    if (cueData->status() != GenericCueData::Complete)
-        m_cueMap.add(cueData.get(), cue.get());
-
-    addCue(cue);
-}
-
-void InbandTextTrack::updateGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
-{
-    RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
-    if (!cue)
-        return;
-
-    updateCueFromCueData(cue.get(), cueData);
-    
-    if (cueData->status() == GenericCueData::Complete)
-        m_cueMap.remove(cueData);
+    setLabel(label);
 }
 
-void InbandTextTrack::removeGenericCue(InbandTextTrackPrivate*, GenericCueData* cueData)
-{
-    RefPtr<TextTrackCueGeneric> cue = m_cueMap.find(cueData);
-    if (cue) {
-        LOG(Media, "InbandTextTrack::removeGenericCue removing cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
-        removeCue(cue.get(), IGNORE_EXCEPTION);
-    } else
-        m_cueMap.remove(cueData);
-}
-
-void InbandTextTrack::addWebVTTCue(InbandTextTrackPrivate* trackPrivate, PassRefPtr<WebVTTCueData> prpCueData)
+void InbandTextTrack::languageChanged(InbandTextTrackPrivate* trackPrivate, const String& language)
 {
     ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
-
-    RefPtr<WebVTTCueData> cueData = prpCueData;
-    if (m_cueMap.find(cueData.get()))
-        return;
-
-    RefPtr<TextTrackCue> cue = TextTrackCue::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
-    cue->setId(cueData->id());
-    cue->setCueSettings(cueData->settings());
-
-    m_cueMap.add(cueData.get(), cue.get());
-    addCue(cue.release());
-}
-
-void InbandTextTrack::removeWebVTTCue(InbandTextTrackPrivate*, WebVTTCueData* cueData)
-{
-    RefPtr<TextTrackCue> cue = m_cueMap.find(cueData);
-    if (cue) {
-        LOG(Media, "InbandTextTrack::removeWebVTTCue removing cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
-        removeCue(cue.get(), IGNORE_EXCEPTION);
-    } else
-        m_cueMap.remove(cueData);
-}
-
-void InbandTextTrack::removeCue(TextTrackCue* cue, ExceptionCode& ec)
-{
-    m_cueMap.remove(cue);
-    TextTrack::removeCue(cue, ec);
+    setLanguage(language);
 }
 
 void InbandTextTrack::willRemoveTextTrackPrivate(InbandTextTrackPrivate* trackPrivate)
index 51e38e07cc75aaa46972c791b21ce4eaa92d16b6..f0897424e63c65405ce1e3c25fcc50bf115810bf 100644 (file)
 
 namespace WebCore {
 
-class Document;
-class InbandTextTrackPrivate;
-class TextTrackCue;
-class WebVTTCueData;
-
-class TextTrackCueMap {
-public:
-    TextTrackCueMap();
-    virtual ~TextTrackCueMap();
-
-    void add(GenericCueData*, TextTrackCueGeneric*);
-    void add(WebVTTCueData*, TextTrackCue*);
-
-    void remove(TextTrackCue*);
-    void remove(GenericCueData*);
-    void remove(WebVTTCueData*);
-
-    PassRefPtr<GenericCueData> findGenericData(TextTrackCue*);
-    PassRefPtr<WebVTTCueData> findWebVTTData(TextTrackCue*);
-    PassRefPtr<TextTrackCueGeneric> find(GenericCueData*);
-    PassRefPtr<TextTrackCue> find(WebVTTCueData*);
-    
-private:
-    typedef HashMap<RefPtr<TextTrackCue>, RefPtr<GenericCueData> > GenericCueToDataMap;
-    typedef HashMap<RefPtr<GenericCueData>, RefPtr<TextTrackCueGeneric> > GenericCueDataToCueMap;
-    typedef HashMap<RefPtr<TextTrackCue>, RefPtr<WebVTTCueData> > WebVTTCueToDataMap;
-    typedef HashMap<RefPtr<WebVTTCueData>, RefPtr<TextTrackCue> > WebVTTCueDataToCueMap;
-
-    GenericCueToDataMap* m_genericCueToDataMap;
-    GenericCueDataToCueMap* m_genericDataToCueMap;
-    WebVTTCueToDataMap* m_webVTTCueToDataMap;
-    WebVTTCueDataToCueMap* m_webVTTDataToCueMap;
-};
-
 class InbandTextTrack : public TextTrack, public InbandTextTrackPrivateClient {
 public:
     static PassRefPtr<InbandTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
@@ -82,26 +48,21 @@ public:
     virtual void setMode(const AtomicString&) OVERRIDE;
     size_t inbandTrackIndex();
 
-private:
+protected:
     InbandTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
 
-    virtual void addGenericCue(InbandTextTrackPrivate*, PassRefPtr<GenericCueData>) OVERRIDE;
-    virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE;
-    virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE;
-    virtual void addWebVTTCue(InbandTextTrackPrivate*, PassRefPtr<WebVTTCueData>) OVERRIDE;
-    virtual void removeWebVTTCue(InbandTextTrackPrivate*, WebVTTCueData*) OVERRIDE;
-    virtual void removeCue(TextTrackCue*, ExceptionCode&) OVERRIDE;
+    RefPtr<InbandTextTrackPrivate> m_private;
+
+private:
+
     virtual void willRemoveTextTrackPrivate(InbandTextTrackPrivate*) OVERRIDE;
 
-    PassRefPtr<TextTrackCueGeneric> createCue(PassRefPtr<GenericCueData>);
-    void updateCueFromCueData(TextTrackCueGeneric*, GenericCueData*);
+    virtual void labelChanged(InbandTextTrackPrivate*, const String& label) OVERRIDE;
+    virtual void languageChanged(InbandTextTrackPrivate*, const String& language) OVERRIDE;
 
 #if USE(PLATFORM_TEXT_TRACK_MENU)
     virtual InbandTextTrackPrivate* privateTrack() OVERRIDE { return m_private.get(); }
 #endif
-
-    TextTrackCueMap m_cueMap;
-    RefPtr<InbandTextTrackPrivate> m_private;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp b/Source/WebCore/html/track/InbandWebVTTTextTrack.cpp
new file mode 100644 (file)
index 0000000..d5690ef
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "InbandWebVTTTextTrack.h"
+
+#include "InbandTextTrackPrivate.h"
+#include "Logging.h"
+#include "WebVTTParser.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+PassRefPtr<InbandTextTrack> InbandWebVTTTextTrack::create(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> playerPrivate)
+{
+    return adoptRef(new InbandWebVTTTextTrack(context, client, playerPrivate));
+}
+
+InbandWebVTTTextTrack::InbandWebVTTTextTrack(ScriptExecutionContext* context, TextTrackClient* client, PassRefPtr<InbandTextTrackPrivate> trackPrivate)
+    : InbandTextTrack(context, client, trackPrivate)
+{
+}
+
+InbandWebVTTTextTrack::~InbandWebVTTTextTrack()
+{
+}
+
+void InbandWebVTTTextTrack::parseWebVTTCueData(InbandTextTrackPrivate* trackPrivate, const char* data, unsigned length)
+{
+    ASSERT_UNUSED(trackPrivate, trackPrivate == m_private);
+    if (!m_webVTTParser)
+        m_webVTTParser = WebVTTParser::create(this, scriptExecutionContext());
+    m_webVTTParser->parseBytes(data, length);
+}
+
+void InbandWebVTTTextTrack::newCuesParsed()
+{
+    Vector<RefPtr<WebVTTCueData> > cues;
+    m_webVTTParser->getNewCues(cues);
+    for (size_t i = 0; i < cues.size(); ++i) {
+        RefPtr<WebVTTCueData> cueData = cues[i];
+        RefPtr<TextTrackCue> cue = TextTrackCue::create(scriptExecutionContext(), cueData->startTime(), cueData->endTime(), cueData->content());
+        cue->setId(cueData->id());
+        cue->setCueSettings(cueData->settings());
+
+        if (hasCue(cue.get(), TextTrackCue::IgnoreDuration)) {
+            LOG(Media, "InbandWebVTTTextTrack::newCuesParsed ignoring already added cue: start=%.2f, end=%.2f, content=\"%s\"\n", cueData->startTime(), cueData->endTime(), cueData->content().utf8().data());
+            return;
+        }
+        addCue(cue.release());
+    }
+}
+
+void InbandWebVTTTextTrack::fileFailedToParse()
+{
+    LOG(Media, "Unable to parse WebVTT stream.");
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/html/track/InbandWebVTTTextTrack.h b/Source/WebCore/html/track/InbandWebVTTTextTrack.h
new file mode 100644 (file)
index 0000000..e7b7a12
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012, 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 InbandWebVTTTextTrack_h
+#define InbandWebVTTTextTrack_h
+
+#if ENABLE(VIDEO_TRACK)
+
+#include "InbandTextTrack.h"
+#include "WebVTTParser.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class InbandWebVTTTextTrack : public InbandTextTrack, private WebVTTParserClient {
+public:
+    static PassRefPtr<InbandTextTrack> create(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+    virtual ~InbandWebVTTTextTrack();
+
+private:
+    InbandWebVTTTextTrack(ScriptExecutionContext*, TextTrackClient*, PassRefPtr<InbandTextTrackPrivate>);
+
+    virtual void parseWebVTTCueData(InbandTextTrackPrivate*, const char* data, unsigned length) OVERRIDE;
+
+    virtual void newCuesParsed() OVERRIDE;
+#if ENABLE(WEBVTT_REGIONS)
+    virtual void newRegionsParsed() OVERRIDE;
+#endif
+    virtual void fileFailedToParse() OVERRIDE;
+
+    virtual void addGenericCue(InbandTextTrackPrivate*, PassRefPtr<GenericCueData>) OVERRIDE { ASSERT_NOT_REACHED(); }
+    virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE { ASSERT_NOT_REACHED(); }
+    virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) OVERRIDE { ASSERT_NOT_REACHED(); }
+
+    OwnPtr<WebVTTParser> m_webVTTParser;
+};
+
+} // namespace WebCore
+
+#endif
+#endif
index 91066eaa3e8c446c3ea6dcb028dc4353cf1dc327..9295aead8577924373bb049dbd137760693b4a22 100644 (file)
@@ -39,10 +39,6 @@ namespace WebCore {
 class InbandTextTrackPrivate : public RefCounted<InbandTextTrackPrivate> {
     WTF_MAKE_NONCOPYABLE(InbandTextTrackPrivate); WTF_MAKE_FAST_ALLOCATED;
 public:
-    static PassRefPtr<InbandTextTrackPrivate> create()
-    {
-        return adoptRef(new InbandTextTrackPrivate());
-    }
     virtual ~InbandTextTrackPrivate() { }
 
     void setClient(InbandTextTrackPrivateClient* client) { m_client = client; }
@@ -78,6 +74,12 @@ public:
 
     virtual int textTrackIndex() const { return 0; }
 
+    enum CueFormat {
+        Generic,
+        WebVTT
+    };
+    CueFormat cueFormat() const { return m_format; }
+
     void willBeRemoved()
     {
         if (m_client)
@@ -85,13 +87,15 @@ public:
     }
 
 protected:
-    InbandTextTrackPrivate()
-        : m_client(0)
+    InbandTextTrackPrivate(CueFormat format)
+        : m_format(format)
+        , m_client(0)
         , m_mode(Disabled)
     {
     }
 
 private:
+    CueFormat m_format;
     InbandTextTrackPrivateClient* m_client;
     Mode m_mode;
 };
index a0478fff0cd1c3e783400af82cd0b981fbad46b0..67b88a555d1f2708d5f337663c9785bea340fbc3 100644 (file)
@@ -139,8 +139,10 @@ public:
     virtual void updateGenericCue(InbandTextTrackPrivate*, GenericCueData*) = 0;
     virtual void removeGenericCue(InbandTextTrackPrivate*, GenericCueData*) = 0;
 
-    virtual void addWebVTTCue(InbandTextTrackPrivate*, PassRefPtr<WebVTTCueData>) = 0;
-    virtual void removeWebVTTCue(InbandTextTrackPrivate*, WebVTTCueData*) = 0;
+    virtual void parseWebVTTCueData(InbandTextTrackPrivate*, const char* data, unsigned length) = 0;
+
+    virtual void labelChanged(InbandTextTrackPrivate*, const String&) = 0;
+    virtual void languageChanged(InbandTextTrackPrivate*, const String&) = 0;
 
     virtual void willRemoveTextTrackPrivate(InbandTextTrackPrivate*) = 0;
 };
index 277d30ee3dfb585f28cdf3f15e04fc63971e6871..c164d4ffb0a622675f10d351130730603207ef35 100644 (file)
@@ -97,7 +97,8 @@ AVFInbandTrackParent::~AVFInbandTrackParent()
 }
 
 InbandTextTrackPrivateAVF::InbandTextTrackPrivateAVF(AVFInbandTrackParent* owner)
-    : m_owner(owner)
+    : InbandTextTrackPrivate(Generic)
+    , m_owner(owner)
     , m_pendingCueStatus(None)
     , m_index(0)
     , m_hasBeenReported(false)
index e9f2b294d9846174b9b7776ae04f59b9c3c6bd62..82ee906f74a297771307070fab5d860b172c06c2 100644 (file)
@@ -183,5 +183,45 @@ template<> void derefGPtr<GstBuffer>(GstBuffer* ptr)
     if (ptr)
         gst_buffer_unref(ptr);
 }
+
+#ifdef GST_API_VERSION_1
+template<> GRefPtr<GstSample> adoptGRef(GstSample* ptr)
+{
+    return GRefPtr<GstSample>(ptr, GRefPtrAdopt);
+}
+
+template<> GstSample* refGPtr<GstSample>(GstSample* ptr)
+{
+    if (ptr)
+        gst_sample_ref(ptr);
+
+    return ptr;
+}
+
+template<> void derefGPtr<GstSample>(GstSample* ptr)
+{
+    if (ptr)
+        gst_sample_unref(ptr);
+}
+#endif
+
+template<> GRefPtr<GstEvent> adoptGRef(GstEvent* ptr)
+{
+    return GRefPtr<GstEvent>(ptr, GRefPtrAdopt);
+}
+
+template<> GstEvent* refGPtr<GstEvent>(GstEvent* ptr)
+{
+    if (ptr)
+        gst_event_ref(ptr);
+
+    return ptr;
+}
+
+template<> void derefGPtr<GstEvent>(GstEvent* ptr)
+{
+    if (ptr)
+        gst_event_unref(ptr);
+}
 }
 #endif // USE(GSTREAMER)
index 002879f4ff4126f468b1af33d10a139dc443141a..41b911d2ffef51cf657e68efbe8a38fda32ae999 100644 (file)
@@ -31,6 +31,10 @@ typedef struct _GstTask GstTask;
 typedef struct _GstBus GstBus;
 typedef struct _GstElementFactory GstElementFactory;
 typedef struct _GstBuffer GstBuffer;
+#ifdef GST_API_VERSION_1
+typedef struct _GstSample GstSample;
+#endif
+typedef struct _GstEvent GstEvent;
 
 namespace WTF {
 
@@ -65,6 +69,16 @@ template<> void derefGPtr<GstElementFactory>(GstElementFactory* ptr);
 template<> GRefPtr<GstBuffer> adoptGRef(GstBuffer* ptr);
 template<> GstBuffer* refGPtr<GstBuffer>(GstBuffer* ptr);
 template<> void derefGPtr<GstBuffer>(GstBuffer* ptr);
+
+#ifdef GST_API_VERSION_1
+template<> GRefPtr<GstSample> adoptGRef(GstSample* ptr);
+template<> GstSample* refGPtr<GstSample>(GstSample* ptr);
+template<> void derefGPtr<GstSample>(GstSample* ptr);
+#endif
+
+template<> GRefPtr<GstEvent> adoptGRef(GstEvent* ptr);
+template<> GstEvent* refGPtr<GstEvent>(GstEvent* ptr);
+template<> void derefGPtr<GstEvent>(GstEvent* ptr);
 }
 
 #endif // USE(GSTREAMER)
index a2bb1fdeb2a04222728cf000e16ece10b959302d..c6e6ea64c72cb08a04c2bcc2ebbabce1b5c69ccb 100644 (file)
     GST_INFO(__VA_ARGS__); \
     LOG_VERBOSE(Media, __VA_ARGS__); } while (0)
 
+#define WARN_MEDIA_MESSAGE(...) do { \
+    GST_WARNING(__VA_ARGS__); \
+    LOG_VERBOSE(Media, __VA_ARGS__); } while (0)
+
 namespace WebCore {
 bool initializeGStreamer();
 }
index 3ee325e6f86e6341525140138b27ee2f63f4db45..24055bb741fd907adc259c5a7843134d6c57eefd 100644 (file)
@@ -29,6 +29,27 @@ namespace WebCore {
 class IntSize;
 };
 
+inline bool webkitGstCheckVersion(guint major, guint minor, guint micro)
+{
+    guint currentMajor, currentMinor, currentMicro, currentNano;
+    gst_version(&currentMajor, &currentMinor, &currentMicro, &currentNano);
+
+    if (currentMajor < major)
+        return false;
+    if (currentMajor > major)
+        return true;
+
+    if (currentMinor < minor)
+        return false;
+    if (currentMinor > minor)
+        return true;
+
+    if (currentMicro < micro)
+        return false;
+
+    return true;
+}
+
 void webkitGstObjectRefSink(GstObject*);
 GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate*, const gchar* name, GstPad* target);
 GRefPtr<GstCaps> webkitGstGetPadCaps(GstPad*);
diff --git a/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp
new file mode 100644 (file)
index 0000000..6641d5a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include "InbandTextTrackPrivateGStreamer.h"
+
+#include "GStreamerUtilities.h"
+#include "Logging.h"
+#include <glib-object.h>
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
+#define GST_CAT_DEFAULT webkit_media_player_debug
+
+namespace WebCore {
+
+static GstPadProbeReturn textTrackPrivateEventCallback(GstPad*, GstPadProbeInfo* info, InbandTextTrackPrivateGStreamer* track)
+{
+    GstEvent* event = gst_pad_probe_info_get_event(info);
+    switch (GST_EVENT_TYPE(event)) {
+    case GST_EVENT_TAG:
+        track->tagsChanged();
+        break;
+    case GST_EVENT_STREAM_START:
+        track->streamChanged();
+        break;
+    default:
+        break;
+    }
+    return GST_PAD_PROBE_OK;
+}
+
+static gboolean textTrackPrivateSampleTimeoutCallback(InbandTextTrackPrivateGStreamer* track)
+{
+    track->notifyTrackOfSample();
+    return FALSE;
+}
+
+static gboolean textTrackPrivateStreamTimeoutCallback(InbandTextTrackPrivateGStreamer* track)
+{
+    track->notifyTrackOfStreamChanged();
+    return FALSE;
+}
+
+static gboolean textTrackPrivateTagsChangeTimeoutCallback(InbandTextTrackPrivateGStreamer* track)
+{
+    track->notifyTrackOfTagsChanged();
+    return FALSE;
+}
+
+InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer(gint index, GRefPtr<GstPad> pad)
+    : InbandTextTrackPrivate(WebVTT)
+    , m_index(index)
+    , m_pad(pad)
+    , m_sampleTimerHandler(0)
+    , m_streamTimerHandler(0)
+    , m_tagTimerHandler(0)
+{
+    m_eventProbe = gst_pad_add_probe(m_pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+        reinterpret_cast<GstPadProbeCallback>(textTrackPrivateEventCallback), this, 0);
+
+    /* We want to check these in case we got events before the track was created */
+    streamChanged();
+    tagsChanged();
+}
+
+InbandTextTrackPrivateGStreamer::~InbandTextTrackPrivateGStreamer()
+{
+    disconnect();
+}
+
+void InbandTextTrackPrivateGStreamer::disconnect()
+{
+    if (!m_pad)
+        return;
+
+    gst_pad_remove_probe(m_pad.get(), m_eventProbe);
+    g_signal_handlers_disconnect_by_func(m_pad.get(),
+        reinterpret_cast<gpointer>(textTrackPrivateEventCallback), this);
+
+    if (m_tagTimerHandler)
+        g_source_remove(m_tagTimerHandler);
+
+    m_pad.clear();
+}
+
+void InbandTextTrackPrivateGStreamer::handleSample(GRefPtr<GstSample> sample)
+{
+    if (m_sampleTimerHandler)
+        g_source_remove(m_sampleTimerHandler);
+    {
+        MutexLocker lock(m_sampleMutex);
+        m_pendingSamples.append(sample);
+    }
+    m_sampleTimerHandler = g_timeout_add(0,
+        reinterpret_cast<GSourceFunc>(textTrackPrivateSampleTimeoutCallback), this);
+}
+
+void InbandTextTrackPrivateGStreamer::streamChanged()
+{
+    if (m_streamTimerHandler)
+        g_source_remove(m_streamTimerHandler);
+    m_streamTimerHandler = g_timeout_add(0,
+        reinterpret_cast<GSourceFunc>(textTrackPrivateStreamTimeoutCallback), this);
+}
+
+void InbandTextTrackPrivateGStreamer::tagsChanged()
+{
+    if (m_tagTimerHandler)
+        g_source_remove(m_tagTimerHandler);
+    m_tagTimerHandler = g_timeout_add(0,
+        reinterpret_cast<GSourceFunc>(textTrackPrivateTagsChangeTimeoutCallback), this);
+}
+
+void InbandTextTrackPrivateGStreamer::notifyTrackOfSample()
+{
+    m_sampleTimerHandler = 0;
+
+    Vector<GRefPtr<GstSample> > samples;
+    {
+        MutexLocker lock(m_sampleMutex);
+        m_pendingSamples.swap(samples);
+    }
+
+    for (size_t i = 0; i < samples.size(); ++i) {
+        GRefPtr<GstSample> sample = samples[i];
+        GstBuffer* buffer = gst_sample_get_buffer(sample.get());
+        if (!buffer) {
+            WARN_MEDIA_MESSAGE("Track %d got sample with no buffer.", m_index);
+            continue;
+        }
+        GstMapInfo info;
+        gboolean ret = gst_buffer_map(buffer, &info, GST_MAP_READ);
+        ASSERT(ret);
+        if (!ret) {
+            WARN_MEDIA_MESSAGE("Track %d unable to map buffer.", m_index);
+            continue;
+        }
+
+        INFO_MEDIA_MESSAGE("Track %d parsing sample: %.*s", m_index, static_cast<int>(info.size),
+            reinterpret_cast<char*>(info.data));
+        client()->parseWebVTTCueData(this, reinterpret_cast<char*>(info.data), info.size);
+        gst_buffer_unmap(buffer, &info);
+    }
+}
+
+void InbandTextTrackPrivateGStreamer::notifyTrackOfStreamChanged()
+{
+    m_streamTimerHandler = 0;
+
+    GRefPtr<GstEvent> event = adoptGRef(gst_pad_get_sticky_event(m_pad.get(),
+        GST_EVENT_STREAM_START, 0));
+    if (!event)
+        return;
+
+    const gchar* streamId;
+    gst_event_parse_stream_start(event.get(), &streamId);
+    INFO_MEDIA_MESSAGE("Track %d got stream start for stream %s.", m_index, streamId);
+    m_streamId = streamId;
+}
+
+void InbandTextTrackPrivateGStreamer::notifyTrackOfTagsChanged()
+{
+    m_tagTimerHandler = 0;
+
+    GRefPtr<GstEvent> event = adoptGRef(gst_pad_get_sticky_event(m_pad.get(), GST_EVENT_TAG, 0));
+    GstTagList* tags = 0;
+    if (event)
+        gst_event_parse_tag(event.get(), &tags);
+
+    String label;
+    String language;
+    if (tags) {
+        gchar* tagValue;
+        if (gst_tag_list_get_string(tags, GST_TAG_TITLE, &tagValue)) {
+            INFO_MEDIA_MESSAGE("Track %d got title %s.", m_index, tagValue);
+            label = tagValue;
+            g_free(tagValue);
+        }
+
+        if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &tagValue)) {
+            INFO_MEDIA_MESSAGE("Track %d got language %s.", m_index, tagValue);
+            language = tagValue;
+            g_free(tagValue);
+        }
+    }
+
+    if (m_label != label) {
+        m_label = label;
+        client()->labelChanged(this, m_label);
+    }
+
+    if (m_language != language) {
+        m_language = language;
+        client()->languageChanged(this, m_language);
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
diff --git a/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h
new file mode 100644 (file)
index 0000000..9014774
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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 InbandTextTrackPrivateGStreamer_h
+#define InbandTextTrackPrivateGStreamer_h
+
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include "GRefPtrGStreamer.h"
+#include "InbandTextTrackPrivate.h"
+
+namespace WebCore {
+
+class MediaPlayerPrivateGStreamer;
+typedef struct _GstSample GstSample;
+
+class InbandTextTrackPrivateGStreamer : public InbandTextTrackPrivate {
+public:
+    static PassRefPtr<InbandTextTrackPrivateGStreamer> create(gint index, GRefPtr<GstPad> pad)
+    {
+        return adoptRef(new InbandTextTrackPrivateGStreamer(index, pad));
+    }
+
+    ~InbandTextTrackPrivateGStreamer();
+
+    GstPad* pad() const { return m_pad.get(); }
+
+    void disconnect();
+
+    virtual AtomicString label() const OVERRIDE { return m_label; }
+    virtual AtomicString language() const OVERRIDE { return m_language; }
+
+    void setIndex(int index) { m_index =  index; }
+    virtual int textTrackIndex() const OVERRIDE { return m_index; }
+    String streamId() const { return m_streamId; }
+
+    void handleSample(GRefPtr<GstSample>);
+    void streamChanged();
+    void tagsChanged();
+    void notifyTrackOfSample();
+    void notifyTrackOfStreamChanged();
+    void notifyTrackOfTagsChanged();
+
+private:
+    InbandTextTrackPrivateGStreamer(gint index, GRefPtr<GstPad>);
+
+    gint m_index;
+    GRefPtr<GstPad> m_pad;
+    AtomicString m_label;
+    AtomicString m_language;
+    guint m_sampleTimerHandler;
+    guint m_streamTimerHandler;
+    guint m_tagTimerHandler;
+    gulong m_eventProbe;
+    Vector<GRefPtr<GstSample> > m_pendingSamples;
+    String m_streamId;
+    Mutex m_sampleMutex;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#endif // InbandTextTrackPrivateGStreamer_h
index de27ee07d5dfad338547a3742cc7e53d58345a4d..17a451774150a8508cc44fb6908bc6b071b8aa2e 100644 (file)
 #include <wtf/gobject/GOwnPtr.h>
 #include <wtf/text/CString.h>
 
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+#include "InbandTextTrackPrivateGStreamer.h"
+#include "TextCombinerGStreamer.h"
+#include "TextSinkGStreamer.h"
+#endif
+
 #ifdef GST_API_VERSION_1
 #include <gst/audio/streamvolume.h>
 #else
@@ -132,6 +138,26 @@ static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateG
     return FALSE;
 }
 
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+static void mediaPlayerPrivateTextChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
+{
+    player->textChanged();
+}
+
+static gboolean mediaPlayerPrivateTextChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+    // This is the callback of the timeout source created in ::textChanged.
+    player->notifyPlayerOfText();
+    return FALSE;
+}
+
+static GstFlowReturn mediaPlayerPrivateNewTextSampleCallback(GObject*, MediaPlayerPrivateGStreamer* player)
+{
+    player->newTextSample();
+    return GST_FLOW_OK;
+}
+#endif
+
 static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsReturn result, gpointer userData)
 {
     MediaPlayerPrivateGStreamer* player = reinterpret_cast<MediaPlayerPrivateGStreamer*>(userData);
@@ -229,6 +255,7 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
     , m_hasVideo(false)
     , m_hasAudio(false)
     , m_audioTimerHandler(0)
+    , m_textTimerHandler(0)
     , m_videoTimerHandler(0)
     , m_webkitAudioSink(0)
     , m_totalBytes(-1)
@@ -240,6 +267,10 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
 
 MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
 {
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+    for (size_t i = 0; i < m_textTracks.size(); ++i)
+        m_textTracks[i]->disconnect();
+#endif
     if (m_fillTimer.isActive())
         m_fillTimer.stop();
 
@@ -261,6 +292,10 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateSourceChangedCallback), this);
         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoChangedCallback), this);
         g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateAudioChangedCallback), this);
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+        g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateNewTextSampleCallback), this);
+        g_signal_handlers_disconnect_by_func(m_playBin.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateTextChangedCallback), this);
+#endif
 
         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
         m_playBin.clear();
@@ -274,6 +309,9 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
 
     if (m_audioTimerHandler)
         g_source_remove(m_audioTimerHandler);
+
+    if (m_textTimerHandler)
+        g_source_remove(m_textTimerHandler);
 }
 
 void MediaPlayerPrivateGStreamer::load(const String& url)
@@ -594,6 +632,81 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
 }
 
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+void MediaPlayerPrivateGStreamer::textChanged()
+{
+    if (m_textTimerHandler)
+        g_source_remove(m_textTimerHandler);
+    m_textTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateTextChangeTimeoutCallback), this);
+}
+
+void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
+{
+    m_textTimerHandler = 0;
+
+    gint numTracks = 0;
+    if (m_playBin)
+        g_object_get(m_playBin.get(), "n-text", &numTracks, NULL);
+
+    for (gint i = 0; i < numTracks; ++i) {
+        GstPad* pad;
+        g_signal_emit_by_name(m_playBin.get(), "get-text-pad", i, &pad, NULL);
+        ASSERT(pad);
+
+        if (i < static_cast<gint>(m_textTracks.size())) {
+            RefPtr<InbandTextTrackPrivateGStreamer> existingTrack = m_textTracks[i];
+            existingTrack->setIndex(i);
+            if (existingTrack->pad() == pad) {
+                gst_object_unref(pad);
+                continue;
+            }
+        }
+
+        RefPtr<InbandTextTrackPrivateGStreamer> track = InbandTextTrackPrivateGStreamer::create(i, adoptGRef(pad));
+        m_textTracks.insert(i, track);
+        m_player->addTextTrack(track.release());
+    }
+
+    while (static_cast<gint>(m_textTracks.size()) > numTracks) {
+        RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks.last();
+        track->disconnect();
+        m_textTracks.removeLast();
+        m_player->removeTextTrack(track.release());
+    }
+}
+
+void MediaPlayerPrivateGStreamer::newTextSample()
+{
+    if (!m_textAppSink)
+        return;
+
+    GRefPtr<GstEvent> streamStartEvent = adoptGRef(
+        gst_pad_get_sticky_event(m_textAppSinkPad.get(), GST_EVENT_STREAM_START, 0));
+
+    GstSample* sample;
+    g_signal_emit_by_name(m_textAppSink.get(), "pull-sample", &sample, NULL);
+    ASSERT(sample);
+
+    if (streamStartEvent) {
+        bool found = FALSE;
+        const gchar* id;
+        gst_event_parse_stream_start(streamStartEvent.get(), &id);
+        for (size_t i = 0; i < m_textTracks.size(); ++i) {
+            RefPtr<InbandTextTrackPrivateGStreamer> track = m_textTracks[i];
+            if (track->streamId() == id) {
+                track->handleSample(sample);
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            WARN_MEDIA_MESSAGE("Got sample with unknown stream ID.");
+    } else
+        WARN_MEDIA_MESSAGE("Unable to handle sample with no stream start event.");
+    gst_sample_unref(sample);
+}
+#endif
+
 void MediaPlayerPrivateGStreamer::setRate(float rate)
 {
     // Avoid useless playback rate update.
@@ -1609,6 +1722,26 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
     g_signal_connect(m_playBin.get(), "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
     g_signal_connect(m_playBin.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
     g_signal_connect(m_playBin.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+    if (webkitGstCheckVersion(1, 1, 2)) {
+        g_signal_connect(m_playBin.get(), "text-changed", G_CALLBACK(mediaPlayerPrivateTextChangedCallback), this);
+
+        GstElement* textCombiner = webkitTextCombinerNew();
+        ASSERT(textCombiner);
+        g_object_set(m_playBin.get(), "text-stream-combiner", textCombiner, NULL);
+
+        m_textAppSink = webkitTextSinkNew();
+        ASSERT(m_textAppSink);
+
+        m_textAppSinkPad = adoptGRef(gst_element_get_static_pad(m_textAppSink.get(), "sink"));
+        ASSERT(m_textAppSinkPad);
+
+        g_object_set(m_textAppSink.get(), "emit-signals", true, "enable-last-sample", false, "caps", gst_caps_new_empty_simple("text/vtt"), NULL);
+        g_signal_connect(m_textAppSink.get(), "new-sample", G_CALLBACK(mediaPlayerPrivateNewTextSampleCallback), this);
+
+        g_object_set(m_playBin.get(), "text-sink", m_textAppSink.get(), NULL);
+    }
+#endif
 
     GstElement* videoElement = createVideoSink(m_playBin.get());
 
index 48284d34fb922f20fb223d2e6d18a77c7b1b6b83..29b2ab712b860bfcf8874ec6b8d91c6b591d2ed2 100644 (file)
@@ -39,6 +39,8 @@ typedef struct _GstElement GstElement;
 
 namespace WebCore {
 
+class InbandTextTrackPrivateGStreamer;
+
 class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase {
 public:
     ~MediaPlayerPrivateGStreamer();
@@ -90,6 +92,14 @@ public:
     void notifyPlayerOfVideo();
     void notifyPlayerOfAudio();
 
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+    void textChanged();
+    void notifyPlayerOfText();
+
+    void newTextSample();
+    void notifyPlayerOfNewTextSample();
+#endif
+
     void sourceChanged();
     GstElement* audioSink() const;
 
@@ -131,6 +141,10 @@ private:
 private:
     GRefPtr<GstElement> m_playBin;
     GRefPtr<GstElement> m_source;
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+    GRefPtr<GstElement> m_textAppSink;
+    GRefPtr<GstPad> m_textAppSinkPad;
+#endif
     float m_seekTime;
     bool m_changingRate;
     float m_endTime;
@@ -160,6 +174,7 @@ private:
     bool m_hasVideo;
     bool m_hasAudio;
     guint m_audioTimerHandler;
+    guint m_textTimerHandler;
     guint m_videoTimerHandler;
     GRefPtr<GstElement> m_webkitAudioSink;
     mutable long m_totalBytes;
@@ -168,6 +183,9 @@ private:
     GstState m_requestedState;
     GRefPtr<GstElement> m_autoAudioSink;
     bool m_missingPlugins;
+#if ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+    Vector<RefPtr<InbandTextTrackPrivateGStreamer> > m_textTracks;
+#endif
 };
 }
 
diff --git a/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp
new file mode 100644 (file)
index 0000000..763b3e3
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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.
+ */
+
+#include "config.h"
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include "TextCombinerGStreamer.h"
+
+static GstStaticPadTemplate sinkTemplate =
+    GST_STATIC_PAD_TEMPLATE("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
+        GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate srcTemplate =
+    GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+        GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC(webkitTextCombinerDebug);
+#define GST_CAT_DEFAULT webkitTextCombinerDebug
+
+#define webkit_text_combiner_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE(WebKitTextCombiner, webkit_text_combiner, GST_TYPE_BIN,
+    GST_DEBUG_CATEGORY_INIT(webkitTextCombinerDebug, "webkittextcombiner", 0,
+        "webkit text combiner"));
+
+
+static void webkit_text_combiner_init(WebKitTextCombiner* combiner)
+{
+    combiner->funnel = gst_element_factory_make("funnel", NULL);
+    ASSERT(combiner->funnel);
+
+    gboolean ret = gst_bin_add(GST_BIN(combiner), combiner->funnel);
+    UNUSED_PARAM(ret);
+    ASSERT(ret);
+
+    GstPad* pad = gst_element_get_static_pad(combiner->funnel, "src");
+    ASSERT(pad);
+
+    ret = gst_element_add_pad(GST_ELEMENT(combiner), gst_ghost_pad_new("src", pad));
+    ASSERT(ret);
+}
+
+static GstPadProbeReturn webkitTextCombinerPadEvent(GstPad* pad, GstPadProbeInfo *info, gpointer)
+{
+    gboolean ret;
+    UNUSED_PARAM(ret);
+    WebKitTextCombiner* combiner = WEBKIT_TEXT_COMBINER(gst_pad_get_parent(pad));
+    ASSERT(combiner);
+
+    GstEvent* event = gst_pad_probe_info_get_event(info);
+    ASSERT(event);
+
+    if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) {
+        GstCaps* caps;
+        gst_event_parse_caps(event, &caps);
+        ASSERT(caps);
+
+        GstPad* target = gst_ghost_pad_get_target(GST_GHOST_PAD(pad));
+        ASSERT(target);
+
+        GstElement* targetParent = gst_pad_get_parent_element(target);
+        ASSERT(targetParent);
+
+        GstCaps* textCaps = gst_caps_new_empty_simple("text/x-raw");
+        if (gst_caps_can_intersect(textCaps, caps)) {
+            /* Caps are plain text, put a WebVTT encoder between the ghostpad and
+             * the funnel */
+            if (targetParent == combiner->funnel) {
+                /* Setup a WebVTT encoder */
+                GstElement* encoder = gst_element_factory_make("webvttenc", NULL);
+                ASSERT(encoder);
+
+                ret = gst_bin_add(GST_BIN(combiner), encoder);
+                ASSERT(ret);
+
+                ret = gst_element_sync_state_with_parent(encoder);
+                ASSERT(ret);
+
+                /* Switch the ghostpad to target the WebVTT encoder */
+                GstPad* sinkPad = gst_element_get_static_pad(encoder, "sink");
+                ASSERT(sinkPad);
+
+                ret = gst_ghost_pad_set_target(GST_GHOST_PAD(pad), sinkPad);
+                ASSERT(ret);
+                gst_object_unref(sinkPad);
+
+                /* Connect the WebVTT encoder to the funnel */
+                GstPad* srcPad = gst_element_get_static_pad(encoder, "src");
+                ASSERT(srcPad);
+
+                ret = GST_PAD_LINK_SUCCESSFUL(gst_pad_link(srcPad, target));
+                ASSERT(ret);
+                gst_object_unref(srcPad);
+            } /* else: pipeline is already correct */
+        } else {
+            /* Caps are not plain text, remove the WebVTT encoder */
+            if (targetParent != combiner->funnel) {
+                /* Get the funnel sink pad */
+                GstPad* srcPad = gst_element_get_static_pad(targetParent, "src");
+                ASSERT(srcPad);
+
+                GstPad* sinkPad = gst_pad_get_peer(srcPad);
+                ASSERT(sinkPad);
+                gst_object_unref(srcPad);
+
+                /* Switch the ghostpad to target the funnel */
+                ret = gst_ghost_pad_set_target(GST_GHOST_PAD(pad), sinkPad);
+                ASSERT(ret);
+                gst_object_unref(sinkPad);
+
+                /* Remove the WebVTT encoder */
+                ret = gst_bin_remove(GST_BIN(combiner), targetParent);
+                ASSERT(ret);
+            } /* else: pipeline is already correct */
+        }
+        gst_caps_unref(textCaps);
+        gst_object_unref(targetParent);
+        gst_object_unref(target);
+    }
+    gst_object_unref(combiner);
+
+    return GST_PAD_PROBE_OK;
+}
+
+static GstPad* webkitTextCombinerRequestNewPad(GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+    gboolean ret;
+    UNUSED_PARAM(ret);
+    ASSERT(templ);
+
+    WebKitTextCombiner* combiner = WEBKIT_TEXT_COMBINER(element);
+    ASSERT(combiner);
+
+    GstPad* pad = gst_element_request_pad(combiner->funnel, templ, name, caps);
+    ASSERT(pad);
+
+    GstPad* ghostPad = gst_ghost_pad_new(NULL, pad);
+    ASSERT(ghostPad);
+
+    gst_pad_add_probe(ghostPad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, webkitTextCombinerPadEvent, NULL, NULL);
+
+    ret = gst_pad_set_active(ghostPad, true);
+    ASSERT(ret);
+
+    ret = gst_element_add_pad(GST_ELEMENT(combiner), ghostPad);
+    ASSERT(ret);
+    return ghostPad;
+}
+
+static void webkitTextCombinerReleasePad(GstElement *element, GstPad *pad)
+{
+    WebKitTextCombiner* combiner = WEBKIT_TEXT_COMBINER(element);
+    GstPad* peer = gst_pad_get_peer(pad);
+    if (peer) {
+        GstElement* parent = gst_pad_get_parent_element(peer);
+        ASSERT(parent);
+        gst_element_release_request_pad(parent, peer);
+        if (parent != combiner->funnel)
+            gst_bin_remove(GST_BIN(combiner), parent);
+    }
+
+    gst_element_remove_pad(element, pad);
+}
+
+static void webkit_text_combiner_class_init(WebKitTextCombinerClass* klass)
+{
+    GstElementClass* elementClass = GST_ELEMENT_CLASS(klass);
+
+    gst_element_class_add_pad_template(elementClass, gst_static_pad_template_get(&sinkTemplate));
+    gst_element_class_add_pad_template(elementClass, gst_static_pad_template_get(&srcTemplate));
+
+    gst_element_class_set_metadata(elementClass, "WebKit text combiner", "Generic",
+        "A funnel that accepts any caps, but converts plain text to WebVTT",
+        "Brendan Long <b.long@cablelabs.com>");
+
+    elementClass->request_new_pad =
+        GST_DEBUG_FUNCPTR(webkitTextCombinerRequestNewPad);
+    elementClass->release_pad =
+        GST_DEBUG_FUNCPTR(webkitTextCombinerReleasePad);
+}
+
+GstElement* webkitTextCombinerNew()
+{
+    return GST_ELEMENT(g_object_new(WEBKIT_TYPE_TEXT_COMBINER, 0));
+}
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
diff --git a/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.h
new file mode 100644 (file)
index 0000000..cf44423
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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 TextCombinerGStreamer_h
+#define TextCombinerGStreamer_h
+
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#define WEBKIT_TYPE_TEXT_COMBINER webkit_text_combiner_get_type()
+
+#define WEBKIT_TEXT_COMBINER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_TEXT_COMBINER, WebKitTextCombiner))
+#define WEBKIT_TEXT_COMBINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_TEXT_COMBINER, WebKitTextCombinerClass))
+#define WEBKIT_IS_TEXT_COMBINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_TEXT_COMBINER))
+#define WEBKIT_IS_TEXT_COMBINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_TEXT_COMBINER))
+#define WEBKIT_TEXT_COMBINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_TEXT_COMBINER, WebKitTextCombinerClass))
+
+typedef struct _WebKitTextCombiner WebKitTextCombiner;
+typedef struct _WebKitTextCombinerClass WebKitTextCombinerClass;
+
+struct _WebKitTextCombiner {
+    GstBin parent;
+
+    GstElement *funnel;
+private:
+
+};
+
+struct _WebKitTextCombinerClass {
+    GstBinClass parentClass;
+
+    // Future padding
+    void (* _webkit_reserved1)(void);
+    void (* _webkit_reserved2)(void);
+    void (* _webkit_reserved3)(void);
+    void (* _webkit_reserved4)(void);
+    void (* _webkit_reserved5)(void);
+    void (* _webkit_reserved6)(void);
+};
+
+GstElement* webkitTextCombinerNew();
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+#endif
diff --git a/Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.cpp
new file mode 100644 (file)
index 0000000..864dd2c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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.
+ */
+
+#include "config.h"
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include "TextSinkGStreamer.h"
+
+GST_DEBUG_CATEGORY_STATIC(webkitTextSinkDebug);
+#define GST_CAT_DEFAULT webkitTextSinkDebug
+
+#define webkit_text_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE(WebKitTextSink, webkit_text_sink, GST_TYPE_APP_SINK,
+    GST_DEBUG_CATEGORY_INIT(webkitTextSinkDebug, "webkittextsink", 0,
+        "webkit text sink"));
+
+enum {
+    Prop0,
+    PropSync,
+    PropLast
+};
+
+static void webkit_text_sink_init(WebKitTextSink* sink)
+{
+    /* We want to get cues as quickly as possible so WebKit has time to handle them,
+     * and we don't want cues to block when they come in the wrong order. */
+    gst_base_sink_set_sync(GST_BASE_SINK(sink), false);
+}
+
+static void webkitTextSinkGetProperty(GObject* object, guint propertyId,
+    GValue* value, GParamSpec* pspec)
+{
+    /* Do nothing with PropSync */
+}
+
+static void webkitTextSinkSetProperty(GObject* object, guint propertyId,
+    const GValue* value, GParamSpec* pspec)
+{
+    /* Do nothing with PropSync */
+}
+
+static gboolean webkitTextSinkQuery(GstElement *element, GstQuery *query)
+{
+    switch (GST_QUERY_TYPE(query)) {
+    case GST_QUERY_DURATION:
+    case GST_QUERY_POSITION:
+        /* Ignore duration and position because we don't want the seek bar to be
+         * based on where the cues are. */
+        return false;
+    default:
+        WebKitTextSink* sink = WEBKIT_TEXT_SINK(element);
+        GstElement* parent = GST_ELEMENT(&sink->parent);
+        return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
+    }
+}
+
+static void webkit_text_sink_class_init(WebKitTextSinkClass* klass)
+{
+    GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
+    GstElementClass* elementClass = GST_ELEMENT_CLASS(klass);
+
+    gst_element_class_set_metadata(elementClass, "WebKit text sink", "Generic",
+        "An appsink that ignores the sync property and position and duration queries",
+        "Brendan Long <b.long@cablelabs.com>");
+
+    gobjectClass->get_property = GST_DEBUG_FUNCPTR(webkitTextSinkGetProperty);
+    gobjectClass->set_property = GST_DEBUG_FUNCPTR(webkitTextSinkSetProperty);
+    elementClass->query = GST_DEBUG_FUNCPTR(webkitTextSinkQuery);
+
+    /* Override "sync" so playsink doesn't mess with our appsink */
+    g_object_class_override_property(gobjectClass, PropSync, "sync");
+}
+
+GstElement* webkitTextSinkNew()
+{
+    return GST_ELEMENT(g_object_new(WEBKIT_TYPE_TEXT_SINK, 0));
+}
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
diff --git a/Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/TextSinkGStreamer.h
new file mode 100644 (file)
index 0000000..6c6b6ab
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Cable Television Laboratories, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 INC. OR ITS 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 TextSinkGStreamer_h
+#define TextSinkGStreamer_h
+
+#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+
+#include <glib-object.h>
+#include <gst/app/gstappsink.h>
+#include <gst/gst.h>
+
+#define WEBKIT_TYPE_TEXT_SINK webkit_text_sink_get_type()
+
+#define WEBKIT_TEXT_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_TEXT_SINK, WebKitTextSink))
+#define WEBKIT_TEXT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_TEXT_SINK, WebKitTextSinkClass))
+#define WEBKIT_IS_TEXT_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_TEXT_SINK))
+#define WEBKIT_IS_TEXT_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_TEXT_SINK))
+#define WEBKIT_TEXT_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_TEXT_SINK, WebKitTextSinkClass))
+
+typedef struct _WebKitTextSink WebKitTextSink;
+typedef struct _WebKitTextSinkClass WebKitTextSinkClass;
+
+struct _WebKitTextSink {
+    GstAppSink parent;
+};
+
+struct _WebKitTextSinkClass {
+    GstAppSinkClass parentClass;
+
+    // Future padding
+    void (* _webkit_reserved1)(void);
+    void (* _webkit_reserved2)(void);
+    void (* _webkit_reserved3)(void);
+    void (* _webkit_reserved4)(void);
+    void (* _webkit_reserved5)(void);
+    void (* _webkit_reserved6)(void);
+};
+
+GstElement* webkitTextSinkNew();
+
+#endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK) && defined(GST_API_VERSION_1)
+#endif