<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[211864] releases/WebKitGTK/webkit-2.14/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/211864">211864</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2017-02-08 03:49:24 -0800 (Wed, 08 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/211627">r211627</a> - [GStreamer] Store preloaded media in webkit's cache
https://bugs.webkit.org/show_bug.cgi?id=119477

Reviewed by Xabier Rodriguez-Calvar.

Files cached on disk by MediaPlayerPrivateGStreamer are deleted only when the player is closed. If the
WebProcess crashed, they're just left there in the cache directory. This patch changes the location
of those temporary files to a proper temporary directory (/var/tmp, as those files aren't actually
reusable, so they don't belong to a cache directory, and /tmp is a bad place because it's RAM-based on
some distros), unlinks (deletes) them right after creation and also deletes any other stalled temporary
file on the old legacy cache directory.

There's no API in GstPlaybin to control the temporary file location, so we do it manually by locating
the GstDownloadBuffer element in the pipeline as soon as it's created, reconfiguring it with the right
temporary file path and deleting the file as soon as it's created.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer): Stop listening to element-added.
(WebCore::MediaPlayerPrivateGStreamer::uriDecodeBinElementAddedCallback): Look for GstDownloadBuffer.
(WebCore::MediaPlayerPrivateGStreamer::downloadBufferFileCreatedCallback): Remove the file after creation.
(WebCore::MediaPlayerPrivateGStreamer::purgeOldDownloadFiles): Delete legacy files.
(WebCore::MediaPlayerPrivateGStreamer::sourceChanged): Listen to element-added signals on GstUriDecodeBin.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: New reference to GstDownloadBuffer.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit214SourceWebCoreChangeLog">releases/WebKitGTK/webkit-2.14/Source/WebCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit214SourceWebCoreplatformgraphicsgstreamerMediaPlayerPrivateGStreamercpp">releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit214SourceWebCoreplatformgraphicsgstreamerMediaPlayerPrivateGStreamerh">releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit214SourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.14/Source/WebCore/ChangeLog (211863 => 211864)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.14/Source/WebCore/ChangeLog        2017-02-08 11:11:02 UTC (rev 211863)
+++ releases/WebKitGTK/webkit-2.14/Source/WebCore/ChangeLog        2017-02-08 11:49:24 UTC (rev 211864)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2017-02-03  Enrique Ocaña González  &lt;eocanha@igalia.com&gt;
+
+        [GStreamer] Store preloaded media in webkit's cache
+        https://bugs.webkit.org/show_bug.cgi?id=119477
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Files cached on disk by MediaPlayerPrivateGStreamer are deleted only when the player is closed. If the
+        WebProcess crashed, they're just left there in the cache directory. This patch changes the location
+        of those temporary files to a proper temporary directory (/var/tmp, as those files aren't actually
+        reusable, so they don't belong to a cache directory, and /tmp is a bad place because it's RAM-based on
+        some distros), unlinks (deletes) them right after creation and also deletes any other stalled temporary
+        file on the old legacy cache directory.
+
+        There's no API in GstPlaybin to control the temporary file location, so we do it manually by locating
+        the GstDownloadBuffer element in the pipeline as soon as it's created, reconfiguring it with the right
+        temporary file path and deleting the file as soon as it's created.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer): Stop listening to element-added.
+        (WebCore::MediaPlayerPrivateGStreamer::uriDecodeBinElementAddedCallback): Look for GstDownloadBuffer.
+        (WebCore::MediaPlayerPrivateGStreamer::downloadBufferFileCreatedCallback): Remove the file after creation.
+        (WebCore::MediaPlayerPrivateGStreamer::purgeOldDownloadFiles): Delete legacy files.
+        (WebCore::MediaPlayerPrivateGStreamer::sourceChanged): Listen to element-added signals on GstUriDecodeBin.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: New reference to GstDownloadBuffer.
+
</ins><span class="cx"> 2017-01-26  Enrique Ocaña González  &lt;eocanha@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GStreamer] ASSERTION FAILED: !g_object_is_floating(ptr) in adoptGRef(GstContext* ptr)
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit214SourceWebCoreplatformgraphicsgstreamerMediaPlayerPrivateGStreamercpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (211863 => 211864)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp        2017-02-08 11:11:02 UTC (rev 211863)
+++ releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp        2017-02-08 11:49:24 UTC (rev 211864)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(VIDEO) &amp;&amp; USE(GSTREAMER)
</span><span class="cx"> 
</span><ins>+#include &quot;FileSystem.h&quot;
</ins><span class="cx"> #include &quot;GStreamerUtilities.h&quot;
</span><span class="cx"> #include &quot;URL.h&quot;
</span><span class="cx"> #include &quot;MIMETypeRegistry.h&quot;
</span><span class="lines">@@ -36,6 +37,7 @@
</span><span class="cx"> #include &quot;SecurityOrigin.h&quot;
</span><span class="cx"> #include &quot;TimeRanges.h&quot;
</span><span class="cx"> #include &quot;WebKitWebSourceGStreamer.h&quot;
</span><ins>+#include &lt;glib.h&gt;
</ins><span class="cx"> #include &lt;gst/gst.h&gt;
</span><span class="cx"> #include &lt;gst/pbutils/missing-plugins.h&gt;
</span><span class="cx"> #include &lt;limits&gt;
</span><span class="lines">@@ -195,6 +197,9 @@
</span><span class="cx">         m_mediaLocations = 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (WEBKIT_IS_WEB_SRC(m_source.get()) &amp;&amp; GST_OBJECT_PARENT(m_source.get()))
+        g_signal_handlers_disconnect_by_func(GST_ELEMENT_PARENT(m_source.get()), reinterpret_cast&lt;gpointer&gt;(uriDecodeBinElementAddedCallback), this);
+
</ins><span class="cx">     if (m_autoAudioSink)
</span><span class="cx">         g_signal_handlers_disconnect_by_func(G_OBJECT(m_autoAudioSink.get()),
</span><span class="cx">             reinterpret_cast&lt;gpointer&gt;(setAudioStreamPropertiesCallback), this);
</span><span class="lines">@@ -1303,13 +1308,75 @@
</span><span class="cx">     player-&gt;sourceChanged();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MediaPlayerPrivateGStreamer::uriDecodeBinElementAddedCallback(GstBin* bin, GstElement* element, MediaPlayerPrivateGStreamer* player)
+{
+    if (g_strcmp0(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(G_OBJECT(element))), &quot;GstDownloadBuffer&quot;))
+        return;
+
+    player-&gt;m_downloadBuffer = element;
+    g_signal_handlers_disconnect_by_func(bin, reinterpret_cast&lt;gpointer&gt;(uriDecodeBinElementAddedCallback), player);
+    g_signal_connect_swapped(element, &quot;notify::temp-location&quot;, G_CALLBACK(downloadBufferFileCreatedCallback), player);
+
+    GUniqueOutPtr&lt;char&gt; oldDownloadTemplate;
+    g_object_get(element, &quot;temp-template&quot;, &amp;oldDownloadTemplate.outPtr(), nullptr);
+
+    GUniquePtr&lt;char&gt; newDownloadTemplate(g_build_filename(G_DIR_SEPARATOR_S, &quot;var&quot;, &quot;tmp&quot;, &quot;WebKit-Media-XXXXXX&quot;, nullptr));
+    g_object_set(element, &quot;temp-template&quot;, newDownloadTemplate.get(), nullptr);
+    GST_TRACE(&quot;Reconfigured file download template from '%s' to '%s'&quot;, oldDownloadTemplate.get(), newDownloadTemplate.get());
+
+    player-&gt;purgeOldDownloadFiles(oldDownloadTemplate.get());
+}
+
+void MediaPlayerPrivateGStreamer::downloadBufferFileCreatedCallback(MediaPlayerPrivateGStreamer* player)
+{
+    ASSERT(player-&gt;m_downloadBuffer);
+
+    g_signal_handlers_disconnect_by_func(player-&gt;m_downloadBuffer.get(), reinterpret_cast&lt;gpointer&gt;(downloadBufferFileCreatedCallback), player);
+
+    GUniqueOutPtr&lt;char&gt; downloadFile;
+    g_object_get(player-&gt;m_downloadBuffer.get(), &quot;temp-location&quot;, &amp;downloadFile.outPtr(), nullptr);
+    player-&gt;m_downloadBuffer = nullptr;
+
+    if (UNLIKELY(!deleteFile(downloadFile.get()))) {
+        GST_WARNING(&quot;Couldn't unlink media temporary file %s after creation&quot;, downloadFile.get());
+        return;
+    }
+
+    GST_TRACE(&quot;Unlinked media temporary file %s after creation&quot;, downloadFile.get());
+}
+
+void MediaPlayerPrivateGStreamer::purgeOldDownloadFiles(const char* downloadFileTemplate)
+{
+    if (!downloadFileTemplate)
+        return;
+
+    GUniquePtr&lt;char&gt; templatePath(g_path_get_dirname(downloadFileTemplate));
+    GUniquePtr&lt;char&gt; templateFile(g_path_get_basename(downloadFileTemplate));
+    String templatePattern = String(templateFile.get()).replace(&quot;X&quot;, &quot;?&quot;);
+
+    for (auto&amp; filePath : listDirectory(templatePath.get(), templatePattern)) {
+        if (UNLIKELY(!deleteFile(filePath))) {
+            GST_WARNING(&quot;Couldn't unlink legacy media temporary file: %s&quot;, filePath.utf8().data());
+            continue;
+        }
+
+        GST_TRACE(&quot;Unlinked legacy media temporary file: %s&quot;, filePath.utf8().data());
+    }
+}
+
</ins><span class="cx"> void MediaPlayerPrivateGStreamer::sourceChanged()
</span><span class="cx"> {
</span><ins>+    if (WEBKIT_IS_WEB_SRC(m_source.get()) &amp;&amp; GST_OBJECT_PARENT(m_source.get()))
+        g_signal_handlers_disconnect_by_func(GST_ELEMENT_PARENT(m_source.get()), reinterpret_cast&lt;gpointer&gt;(uriDecodeBinElementAddedCallback), this);
+
</ins><span class="cx">     m_source.clear();
</span><span class="cx">     g_object_get(m_pipeline.get(), &quot;source&quot;, &amp;m_source.outPtr(), nullptr);
</span><span class="cx"> 
</span><del>-    if (WEBKIT_IS_WEB_SRC(m_source.get()))
</del><ins>+    if (WEBKIT_IS_WEB_SRC(m_source.get())) {
</ins><span class="cx">         webKitWebSrcSetMediaPlayer(WEBKIT_WEB_SRC(m_source.get()), m_player);
</span><ins>+        g_signal_connect(GST_ELEMENT_PARENT(m_source.get()), &quot;element-added&quot;, G_CALLBACK(uriDecodeBinElementAddedCallback), this);
+    }
+
</ins><span class="cx"> #if ENABLE(MEDIA_SOURCE)
</span><span class="cx">     if (m_mediaSource &amp;&amp; WEBKIT_IS_MEDIA_SRC(m_source.get())) {
</span><span class="cx">         MediaSourceGStreamer::open(m_mediaSource.get(), WEBKIT_MEDIA_SRC(m_source.get()));
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit214SourceWebCoreplatformgraphicsgstreamerMediaPlayerPrivateGStreamerh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h (211863 => 211864)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h        2017-02-08 11:11:02 UTC (rev 211863)
+++ releases/WebKitGTK/webkit-2.14/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h        2017-02-08 11:49:24 UTC (rev 211864)
</span><span class="lines">@@ -170,6 +170,10 @@
</span><span class="cx">     MediaTime totalFrameDelay() override { return MediaTime::zeroTime(); }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    void purgeOldDownloadFiles(const char*);
+    static void uriDecodeBinElementAddedCallback(GstBin*, GstElement*, MediaPlayerPrivateGStreamer*);
+    static void downloadBufferFileCreatedCallback(MediaPlayerPrivateGStreamer*);
+
</ins><span class="cx">     void readyTimerFired();
</span><span class="cx"> 
</span><span class="cx">     void notifyPlayerOfVideo();
</span><span class="lines">@@ -238,6 +242,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     GstState m_requestedState;
</span><span class="cx">     GRefPtr&lt;GstElement&gt; m_autoAudioSink;
</span><ins>+    GRefPtr&lt;GstElement&gt; m_downloadBuffer;
</ins><span class="cx">     RefPtr&lt;MediaPlayerRequestInstallMissingPluginsCallback&gt; m_missingPluginsCallback;
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">     Vector&lt;RefPtr&lt;AudioTrackPrivateGStreamer&gt;&gt; m_audioTracks;
</span></span></pre>
</div>
</div>

</body>
</html>