+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
--- /dev/null
+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);
+}
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
--- /dev/null
+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
+
--- /dev/null
+<!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>
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 ]
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
+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
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 \
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
# ---
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
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 += \
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 \
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 \
<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" />
<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>
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;
};
#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"
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#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)
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)
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>);
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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; }
virtual int textTrackIndex() const { return 0; }
+ enum CueFormat {
+ Generic,
+ WebVTT
+ };
+ CueFormat cueFormat() const { return m_format; }
+
void willBeRemoved()
{
if (m_client)
}
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;
};
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;
};
}
InbandTextTrackPrivateAVF::InbandTextTrackPrivateAVF(AVFInbandTrackParent* owner)
- : m_owner(owner)
+ : InbandTextTrackPrivate(Generic)
+ , m_owner(owner)
, m_pendingCueStatus(None)
, m_index(0)
, m_hasBeenReported(false)
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)
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 {
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)
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();
}
class IntSize;
};
+inline bool webkitGstCheckVersion(guint major, guint minor, guint micro)
+{
+ guint currentMajor, currentMinor, currentMicro, currentNano;
+ gst_version(¤tMajor, ¤tMinor, ¤tMicro, ¤tNano);
+
+ 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*);
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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
#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
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);
, m_hasVideo(false)
, m_hasAudio(false)
, m_audioTimerHandler(0)
+ , m_textTimerHandler(0)
, m_videoTimerHandler(0)
, m_webkitAudioSink(0)
, m_totalBytes(-1)
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();
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();
if (m_audioTimerHandler)
g_source_remove(m_audioTimerHandler);
+
+ if (m_textTimerHandler)
+ g_source_remove(m_textTimerHandler);
}
void MediaPlayerPrivateGStreamer::load(const String& url)
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.
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());
namespace WebCore {
+class InbandTextTrackPrivateGStreamer;
+
class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateGStreamerBase {
public:
~MediaPlayerPrivateGStreamer();
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;
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;
bool m_hasVideo;
bool m_hasAudio;
guint m_audioTimerHandler;
+ guint m_textTimerHandler;
guint m_videoTimerHandler;
GRefPtr<GstElement> m_webkitAudioSink;
mutable long m_totalBytes;
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
};
}
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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