Diff
Modified: trunk/LayoutTests/ChangeLog (272054 => 272055)
--- trunk/LayoutTests/ChangeLog 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/LayoutTests/ChangeLog 2021-01-29 10:36:36 UTC (rev 272055)
@@ -1,3 +1,13 @@
+2021-01-29 Philippe Normand <[email protected]>
+
+ [GStreamer][Playbin3] Support for CEA-608 closed captioned media
+ https://bugs.webkit.org/show_bug.cgi?id=220654
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ * media/track/track-in-band-style-expected.txt:
+ * media/track/track-in-band-style.html:
+
2021-01-28 Sergio Villar Senin <[email protected]>
[css-flexbox] REGRESSION(r266695): content inside a `<button>` inside a flex container has a height of `0` without a declared `min-height`
Modified: trunk/LayoutTests/media/track/track-in-band-style-expected.txt (272054 => 272055)
--- trunk/LayoutTests/media/track/track-in-band-style-expected.txt 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/LayoutTests/media/track/track-in-band-style-expected.txt 2021-01-29 10:36:36 UTC (rev 272055)
@@ -13,7 +13,7 @@
EVENT(cuechange)
** Test current cue colors
-EXPECTED (cueNode.style.color == 'rgb(255, 255, 255)') OK
-EXPECTED (cueNode.style.backgroundColor == 'rgb(0, 0, 0)') OK
+EXPECTED (getComputedStyle(cueNode).color == 'rgb(255, 255, 255)') OK
+EXPECTED (getComputedStyle(cueNode).backgroundColor == 'rgba(0, 0, 0, 0.8)') OK
END OF TEST
Modified: trunk/LayoutTests/media/track/track-in-band-style.html (272054 => 272055)
--- trunk/LayoutTests/media/track/track-in-band-style.html 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/LayoutTests/media/track/track-in-band-style.html 2021-01-29 10:36:36 UTC (rev 272055)
@@ -25,9 +25,9 @@
}
consoleWrite("<br><i>** Test current cue colors<" + "/i>");
- testExpected("cueNode.style.color", "rgb(255, 255, 255)");
- testExpected("cueNode.style.backgroundColor", "rgb(0, 0, 0)");
-
+ testExpected("getComputedStyle(cueNode).color", "rgb(255, 255, 255)");
+ testExpected("getComputedStyle(cueNode).backgroundColor", "rgba(0, 0, 0, 0.8)");
+
endTest();
}
Modified: trunk/Source/WebCore/ChangeLog (272054 => 272055)
--- trunk/Source/WebCore/ChangeLog 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/ChangeLog 2021-01-29 10:36:36 UTC (rev 272055)
@@ -1,3 +1,38 @@
+2021-01-29 Philippe Normand <[email protected]>
+
+ [GStreamer][Playbin3] Support for CEA-608 closed captioned media
+ https://bugs.webkit.org/show_bug.cgi?id=220654
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ Playbin2 currently doesn't support closed-caption formats such as CEA-608 and CEA-708.
+ However playbin3's decodebin3 will expose a source pad for these, so our text combiner can
+ handle this format, by adding a custom encoder that converts CEA-608 to WebVTT.
+
+ No new tests, although media/media-captions.html and media/track/track-in-band-style.html
+ will now pass when this env var is set WEBKIT_GST_USE_PLAYBIN3=1.
+
+ * Modules/mediacontrols/mediaControlsAdwaita.css: Synchronize text-track-container and cue
+ CSS with mediaControlsBase.css.
+ (video::-webkit-media-text-track-container,):
+ (video::-webkit-media-text-track-container):
+ (video::cue):
+ (video::cue(:future)):
+ * platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp: Set track kind according
+ to the GstStream format this track represents.
+ (WebCore::InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer):
+ * platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h:
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: Drive-by, check
+ WEBKIT_GST_USE_PLAYBIN3 contents and sprinkle a few more debug calls.
+ (WebCore::MediaPlayerPrivateGStreamer::doSeek):
+ (WebCore::MediaPlayerPrivateGStreamer::timeChanged):
+ (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
+ * platform/graphics/gstreamer/TextCombinerGStreamer.cpp: Plug custom encoder handling
+ conversion of CEA-608 to WebVTT.
+ (webKitTextCombinerHandleCapsEvent):
+ (webkitTextCombinerReleasePad):
+ (webKitTextCombinerConstructed):
+
2021-01-28 Sergio Villar Senin <[email protected]>
[css-flexbox] REGRESSION(r266695): content inside a `<button>` inside a flex container has a height of `0` without a declared `min-height`
Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsAdwaita.css (272054 => 272055)
--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsAdwaita.css 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsAdwaita.css 2021-01-29 10:36:36 UTC (rev 272055)
@@ -469,3 +469,38 @@
video::-webkit-media-controls-panel button[disabled] {
filter: brightness(50%);
}
+
+video::-webkit-media-text-track-container,
+audio::-webkit-media-text-track-container {
+ position: relative;
+ -webkit-flex: 1 1 auto;
+}
+
+video::-webkit-media-text-track-container {
+ overflow: hidden;
+ padding-bottom: 5px;
+ z-index: 0;
+
+ text-align: center;
+ color: rgba(255, 255, 255, 1);
+
+ letter-spacing: normal;
+ word-spacing: normal;
+ text-transform: none;
+ text-indent: 0;
+ text-decoration: none;
+ pointer-events: none;
+ -webkit-user-select: none;
+
+ flex: 1 1 auto;
+
+ -webkit-line-box-contain: block inline-box replaced;
+}
+
+video::cue {
+ background-color: rgba(0, 0, 0, 0.8);
+}
+
+video::cue(:future) {
+ color: gray;
+}
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp (272054 => 272055)
--- trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp 2021-01-29 10:36:36 UTC (rev 272055)
@@ -42,6 +42,7 @@
InbandTextTrackPrivateGStreamer::InbandTextTrackPrivateGStreamer(gint index, GRefPtr<GstPad> pad)
: InbandTextTrackPrivate(CueFormat::WebVTT)
, TrackPrivateBaseGStreamer(this, index, pad)
+ , m_kind(Kind::Subtitles)
{
m_eventProbe = gst_pad_add_probe(m_pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, [] (GstPad*, GstPadProbeInfo* info, gpointer userData) -> GstPadProbeReturn {
auto* track = static_cast<InbandTextTrackPrivateGStreamer*>(userData);
@@ -64,6 +65,11 @@
{
m_streamId = gst_stream_get_stream_id(stream.get());
GST_INFO("Track %d got stream start for stream %s.", m_index, m_streamId.utf8().data());
+
+ GST_DEBUG("Stream %" GST_PTR_FORMAT, stream.get());
+ auto caps = adoptGRef(gst_stream_get_caps(stream.get()));
+ const char* mediaType = capsMediaType(caps.get());
+ m_kind = g_str_has_prefix(mediaType, "closedcaption/") ? Kind::Captions : Kind::Subtitles;
}
void InbandTextTrackPrivateGStreamer::disconnect()
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h (272054 => 272055)
--- trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.h 2021-01-29 10:36:36 UTC (rev 272055)
@@ -51,6 +51,8 @@
void disconnect() override;
+ Kind kind() const override { return m_kind; }
+
AtomString label() const override { return m_label; }
AtomString language() const override { return m_language; }
@@ -71,6 +73,7 @@
gulong m_eventProbe;
Vector<GRefPtr<GstSample>> m_pendingSamples;
String m_streamId;
+ Kind m_kind;
Lock m_sampleMutex;
};
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (272054 => 272055)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2021-01-29 10:36:36 UTC (rev 272055)
@@ -488,6 +488,7 @@
if (!rate)
rate = 1.0;
+ GST_DEBUG_OBJECT(pipeline(), "[Seek] Performing actual seek to %" GST_TIME_FORMAT " (endTime: %" GST_TIME_FORMAT ") at rate %f", GST_TIME_ARGS(toGstClockTime(startTime)), GST_TIME_ARGS(toGstClockTime(endTime)), rate);
return gst_element_seek(m_pipeline.get(), rate, GST_FORMAT_TIME, seekType,
GST_SEEK_TYPE_SET, toGstClockTime(startTime), GST_SEEK_TYPE_SET, toGstClockTime(endTime));
}
@@ -1313,6 +1314,7 @@
void MediaPlayerPrivateGStreamer::timeChanged()
{
updateStates();
+ GST_DEBUG_OBJECT(pipeline(), "Emitting timeChanged notification");
m_player->timeChanged();
}
@@ -2699,7 +2701,8 @@
// MSE doesn't support playbin3. Mediastream requires playbin3. Regular
// playback can use playbin3 on-demand with the WEBKIT_GST_USE_PLAYBIN3
// environment variable.
- if ((!isMediaSource() && g_getenv("WEBKIT_GST_USE_PLAYBIN3")) || url.protocolIs("mediastream"))
+ const char* usePlaybin3 = g_getenv("WEBKIT_GST_USE_PLAYBIN3");
+ if ((!isMediaSource() && usePlaybin3 && equal(usePlaybin3, "1")) || url.protocolIs("mediastream"))
playbinName = "playbin3";
if (m_pipeline) {
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp (272054 => 272055)
--- trunk/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp 2021-01-29 10:01:27 UTC (rev 272054)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/TextCombinerGStreamer.cpp 2021-01-29 10:36:36 UTC (rev 272055)
@@ -64,6 +64,7 @@
GRefPtr<GstPad> internalPad;
g_object_get(combinerPad, "inner-combiner-pad", &internalPad.outPtr(), nullptr);
+ auto cea608Caps = adoptGRef(gst_caps_new_empty_simple("closedcaption/x-cea-608"));
auto textCaps = adoptGRef(gst_caps_new_empty_simple("text/x-raw"));
if (gst_caps_can_intersect(textCaps.get(), caps)) {
// Caps are plain text, we want a WebVTT encoder between the ghostpad and the combinerElement.
@@ -87,12 +88,48 @@
gst_pad_link(srcPad.get(), internalPad.get());
} // Else: pipeline is already correct.
+ } else if (gst_caps_can_intersect(cea608Caps.get(), caps)) {
+ if (!isGStreamerPluginAvailable("rsclosedcaption") || !isGStreamerPluginAvailable("closedcaption")) {
+ WTFLogAlways("GStreamer closedcaption plugins are missing. Please install gst-plugins-bad and gst-plugins-rs");
+ return;
+ }
+
+ GST_DEBUG_OBJECT(combiner, "Converting CEA-608 closed captions to WebVTT.");
+ auto* encoder = gst_bin_new(nullptr);
+ auto* queue = gst_element_factory_make("queue", nullptr);
+ auto* converter = gst_element_factory_make("ccconverter", nullptr);
+ auto* rawCapsFilter = gst_element_factory_make("capsfilter", nullptr);
+ auto* webvttEncoder = gst_element_factory_make("cea608tott", nullptr);
+ auto* vttCapsFilter = gst_element_factory_make("capsfilter", nullptr);
+
+ auto rawCaps = adoptGRef(gst_caps_new_simple("closedcaption/x-cea-608", "format", G_TYPE_STRING, "raw", nullptr));
+ g_object_set(rawCapsFilter, "caps", rawCaps.get(), nullptr);
+ auto vttCaps = adoptGRef(gst_caps_new_empty_simple("application/x-subtitle-vtt"));
+ g_object_set(vttCapsFilter, "caps", vttCaps.get(), nullptr);
+
+ gst_bin_add_many(GST_BIN_CAST(encoder), queue, converter, rawCapsFilter, webvttEncoder, vttCapsFilter, nullptr);
+ gst_element_link_many(queue, converter, rawCapsFilter, webvttEncoder, vttCapsFilter, nullptr);
+
+ auto encoderSinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink"));
+ auto* ghostSinkPad = gst_ghost_pad_new("sink", encoderSinkPad.get());
+ gst_element_add_pad(encoder, ghostSinkPad);
+
+ auto encoderSrcPad = adoptGRef(gst_element_get_static_pad(vttCapsFilter, "src"));
+ auto* ghostSrcPad = gst_ghost_pad_new("src", encoderSrcPad.get());
+ gst_element_add_pad(encoder, ghostSrcPad);
+
+ gst_bin_add(GST_BIN_CAST(combiner), encoder);
+ gst_element_sync_state_with_parent(encoder);
+
+ gst_ghost_pad_set_target(GST_GHOST_PAD(pad), ghostSinkPad);
+ gst_pad_link(ghostSrcPad, internalPad.get());
} else {
- // Caps are not plain text, we assume it's WebVTT.
+ // Caps are not plain text or CEA-608, we assume it's WebVTT.
// Remove the WebVTT encoder if present.
- if (target && gstElementFactoryEquals(targetParent.get(), "webvttenc"_s)) {
+ if (target && targetParent) {
GST_DEBUG_OBJECT(combiner, "Removing WebVTT encoder");
+ gst_element_set_state(targetParent.get(), GST_STATE_NULL);
gst_bin_remove(GST_BIN_CAST(combiner), targetParent.get());
target = nullptr;
targetParent = nullptr;
@@ -131,7 +168,7 @@
if (auto target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD(pad)))) {
auto parent = adoptGRef(gst_pad_get_parent_element(target.get()));
ASSERT(parent);
- if (gstElementFactoryEquals(parent.get(), "webvttenc"_s)) {
+ if (parent) {
gst_element_set_state(parent.get(), GST_STATE_NULL);
gst_bin_remove(GST_BIN_CAST(combiner), parent.get());
}
@@ -150,9 +187,9 @@
auto* combiner = WEBKIT_TEXT_COMBINER(object);
auto* priv = combiner->priv;
- // For now a funnel is used, but a better combiner, compatible with playbin3 use-cases, would be concat.
- priv->combinerElement = gst_element_factory_make("funnel", nullptr);
+ priv->combinerElement = gst_element_factory_make("concat", nullptr);
ASSERT(priv->combinerElement);
+ g_object_set(priv->combinerElement.get(), "adjust-base", FALSE, nullptr);
gst_bin_add(GST_BIN_CAST(combiner), priv->combinerElement.get());