2011-04-06  Philippe Normand  <pnormand@igalia.com>

        Reviewed by Martin Robinson.

        [GStreamer] RTSP playback broken
        https://bugs.webkit.org/show_bug.cgi?id=56930

        Rely on {audio,video}-changed playbin2 signals instead of the
        -tags-changed signals because some media don't provide tags and
        then can trick the media-player to not paint video, for instance.

        Also trigger a video size calculation after the video sink
        negotiated its caps. This is useful in the cases where
        audio-changed signal is emitted but the video sink takes more time
        to negociate caps with its peer.

        This patch also fixes the rtsp manual-test with a new stream url
        which seems to be more permanent than the previous WWDC keynote
        stream.

        * manual-tests/video-rtsp.html:
        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
        (WebCore::mediaPlayerPrivateVideoChangedCallback):
        (WebCore::mediaPlayerPrivateAudioChangedCallback):
        (WebCore::mediaPlayerPrivateAudioChangeTimeoutCallback):
        (WebCore::mediaPlayerPrivateVideoChangeTimeoutCallback):
        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
        (WebCore::MediaPlayerPrivateGStreamer::naturalSize):
        (WebCore::MediaPlayerPrivateGStreamer::videoChanged):
        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfVideo):
        (WebCore::MediaPlayerPrivateGStreamer::audioChanged):
        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfAudio):
        (WebCore::MediaPlayerPrivateGStreamer::paint):
        (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@83566 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index c06b7de..b5f66de 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,40 @@
+2011-04-06  Philippe Normand  <pnormand@igalia.com>
+
+        Reviewed by Martin Robinson.
+
+        [GStreamer] RTSP playback broken
+        https://bugs.webkit.org/show_bug.cgi?id=56930
+
+        Rely on {audio,video}-changed playbin2 signals instead of the
+        -tags-changed signals because some media don't provide tags and
+        then can trick the media-player to not paint video, for instance.
+
+        Also trigger a video size calculation after the video sink
+        negotiated its caps. This is useful in the cases where
+        audio-changed signal is emitted but the video sink takes more time
+        to negociate caps with its peer.
+
+        This patch also fixes the rtsp manual-test with a new stream url
+        which seems to be more permanent than the previous WWDC keynote
+        stream.
+
+        * manual-tests/video-rtsp.html:
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::mediaPlayerPrivateVideoChangedCallback):
+        (WebCore::mediaPlayerPrivateAudioChangedCallback):
+        (WebCore::mediaPlayerPrivateAudioChangeTimeoutCallback):
+        (WebCore::mediaPlayerPrivateVideoChangeTimeoutCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::naturalSize):
+        (WebCore::MediaPlayerPrivateGStreamer::videoChanged):
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfVideo):
+        (WebCore::MediaPlayerPrivateGStreamer::audioChanged):
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfAudio):
+        (WebCore::MediaPlayerPrivateGStreamer::paint):
+        (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+
 2011-04-12  Vsevolod Vlasov  <vsevik@chromium.org>
 
         Reviewed by Pavel Feldman.
diff --git a/Source/WebCore/manual-tests/video-rtsp.html b/Source/WebCore/manual-tests/video-rtsp.html
index 4fff987..f500f69 100644
--- a/Source/WebCore/manual-tests/video-rtsp.html
+++ b/Source/WebCore/manual-tests/video-rtsp.html
@@ -3,9 +3,7 @@
 <title>RTSP playback test</title>
 </head>
 <body>
-<video with=640 height=352 autoplay controls src="rtsp://a2047.v1411b.c1411.g.vq.akamaistream.net/5/2047/1411/2_h264_650/1a1a1ae454c430950065de4cbb2f94c226950c7ae655b61a48a91475e243acda3dac194879adde0f/wwdc_2006_2_650.mov"></video>
-<p>Test that QuickTime file with RTSP URL loads.<p>
-<script>start()</script>
-<pre id="console"></pre>
+<video width=400 height=300 preload=none autoplay src="rtsp://dmzosx001.dpa.act.gov.au/medium"></video>
+<p>Test that RTSP URL loads.<p>
 </body>
 </html>
diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
index 85787c7..ee3d473 100644
--- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
@@ -184,55 +184,60 @@
     }
 }
 
-void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
+static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, gpointer data)
 {
     // This is called when playbin receives the notify::volume signal.
     MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
     mp->volumeChanged();
 }
 
-gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+static gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
 {
     // This is the callback of the timeout source created in ::volumeChanged.
     player->notifyPlayerOfVolumeChange();
     return FALSE;
 }
 
-void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
+static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, gpointer data)
 {
     // This is called when playbin receives the notify::mute signal.
     MediaPlayerPrivateGStreamer* mp = reinterpret_cast<MediaPlayerPrivateGStreamer*>(data);
     mp->muteChanged();
 }
 
-gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+static gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
 {
     // This is the callback of the timeout source created in ::muteChanged.
     player->notifyPlayerOfMute();
     return FALSE;
 }
 
-void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player)
+static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
 {
-    player->videoTagsChanged(streamId);
+    player->videoChanged();
 }
 
-void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint streamId, MediaPlayerPrivateGStreamer* player)
+static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
 {
-    player->audioTagsChanged(streamId);
+    player->videoChanged();
 }
 
-gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
 {
-    // This is the callback of the timeout source created in ::audioTagsChanged.
-    player->notifyPlayerOfAudioTags();
+    player->audioChanged();
+}
+
+static gboolean mediaPlayerPrivateAudioChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+    // This is the callback of the timeout source created in ::audioChanged.
+    player->notifyPlayerOfAudio();
     return FALSE;
 }
 
-gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+static gboolean mediaPlayerPrivateVideoChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player)
 {
-    // This is the callback of the timeout source created in ::videoTagsChanged.
-    player->notifyPlayerOfVideoTags();
+    // This is the callback of the timeout source created in ::videoChanged.
+    player->notifyPlayerOfVideo();
     return FALSE;
 }
 
@@ -347,8 +352,8 @@
     , m_muteTimerHandler(0)
     , m_hasVideo(false)
     , m_hasAudio(false)
-    , m_audioTagsTimerHandler(0)
-    , m_videoTagsTimerHandler(0)
+    , m_audioTimerHandler(0)
+    , m_videoTimerHandler(0)
     , m_webkitAudioSink(0)
 {
     if (doGstInit())
@@ -393,11 +398,11 @@
     if (m_volumeTimerHandler)
         g_source_remove(m_volumeTimerHandler);
 
-    if (m_videoTagsTimerHandler)
-        g_source_remove(m_videoTagsTimerHandler);
+    if (m_videoTimerHandler)
+        g_source_remove(m_videoTimerHandler);
 
-    if (m_audioTagsTimerHandler)
-        g_source_remove(m_audioTagsTimerHandler);
+    if (m_audioTimerHandler)
+        g_source_remove(m_audioTimerHandler);
 }
 
 void MediaPlayerPrivateGStreamer::load(const String& url)
@@ -583,6 +588,7 @@
         || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
                                                     &pixelAspectRatioDenominator)) {
         gst_object_unref(GST_OBJECT(pad));
+        // The video-sink has likely not yet negotiated its caps.
         return IntSize();
     }
 
@@ -619,39 +625,40 @@
     return IntSize(static_cast<int>(width), static_cast<int>(height));
 }
 
-void MediaPlayerPrivateGStreamer::videoTagsChanged(gint streamId)
+void MediaPlayerPrivateGStreamer::videoChanged()
 {
-    if (m_videoTagsTimerHandler)
-        g_source_remove(m_videoTagsTimerHandler);
-    m_videoTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoTagsChangeTimeoutCallback), this);
+    if (m_videoTimerHandler)
+        g_source_remove(m_videoTimerHandler);
+    m_videoTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateVideoChangeTimeoutCallback), this);
 }
 
-void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoTags()
+void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
 {
-    m_videoTagsTimerHandler = 0;
+    m_videoTimerHandler = 0;
 
-    gint currentVideo = -1;
+    gint videoTracks = 0;
     if (m_playBin)
-        g_object_get(m_playBin, "current-video", &currentVideo, NULL);
-    m_hasVideo = currentVideo > -1;
+        g_object_get(m_playBin, "n-video", &videoTracks, NULL);
+
+    m_hasVideo = videoTracks > 0;
     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
 }
 
-void MediaPlayerPrivateGStreamer::audioTagsChanged(gint streamId)
+void MediaPlayerPrivateGStreamer::audioChanged()
 {
-    if (m_audioTagsTimerHandler)
-        g_source_remove(m_audioTagsTimerHandler);
-    m_audioTagsTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioTagsChangeTimeoutCallback), this);
+    if (m_audioTimerHandler)
+        g_source_remove(m_audioTimerHandler);
+    m_audioTimerHandler = g_timeout_add(0, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateAudioChangeTimeoutCallback), this);
 }
 
-void MediaPlayerPrivateGStreamer::notifyPlayerOfAudioTags()
+void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
 {
-    m_audioTagsTimerHandler = 0;
+    m_audioTimerHandler = 0;
 
-    gint currentAudio = -1;
+    gint audioTracks = 0;
     if (m_playBin)
-        g_object_get(m_playBin, "current-audio", &currentAudio, NULL);
-    m_hasAudio = currentAudio > -1;
+        g_object_get(m_playBin, "n-audio", &audioTracks, NULL);
+    m_hasAudio = audioTracks > 0;
     m_player->mediaPlayerClient()->mediaPlayerEngineUpdated(m_player);
 }
 
@@ -1420,6 +1427,7 @@
 
     if (!m_player->visible())
         return;
+
     if (!m_buffer)
         return;
 
@@ -1645,8 +1653,8 @@
     g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
     g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
     g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
-    g_signal_connect(m_playBin, "video-tags-changed", G_CALLBACK(mediaPlayerPrivateVideoTagsChangedCallback), this);
-    g_signal_connect(m_playBin, "audio-tags-changed", G_CALLBACK(mediaPlayerPrivateAudioTagsChangedCallback), this);
+    g_signal_connect(m_playBin, "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
+    g_signal_connect(m_playBin, "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
 
     m_webkitVideoSink = webkit_video_sink_new();
 
@@ -1722,6 +1730,14 @@
 
     // Set the bin as video sink of playbin.
     g_object_set(m_playBin, "video-sink", m_videoSinkBin, NULL);
+
+
+    pad = gst_element_get_static_pad(m_webkitVideoSink, "sink");
+    if (pad) {
+        g_signal_connect(pad, "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
+        gst_object_unref(GST_OBJECT(pad));
+    }
+
 }
 
 }
diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
index 680e815..7a9ca7f 100644
--- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
@@ -46,16 +46,7 @@
 class MediaPlayerPrivateGStreamer;
 
 gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
-void mediaPlayerPrivateVolumeChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
-void mediaPlayerPrivateMuteChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
 void mediaPlayerPrivateSourceChangedCallback(GObject* element, GParamSpec* pspec, gpointer data);
-void mediaPlayerPrivateVideoTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*);
-void mediaPlayerPrivateAudioTagsChangedCallback(GObject* element, gint, MediaPlayerPrivateGStreamer*);
-gboolean mediaPlayerPrivateAudioTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player);
-gboolean mediaPlayerPrivateVideoTagsChangeTimeoutCallback(MediaPlayerPrivateGStreamer* player);
-
-gboolean mediaPlayerPrivateVolumeChangeTimeoutCallback(MediaPlayerPrivateGStreamer*);
-gboolean mediaPlayerPrivateMuteChangeTimeoutCallback(MediaPlayerPrivateGStreamer*);
 
 class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface {
         friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
@@ -130,10 +121,10 @@
             GstElement* pipeline() const { return m_playBin; }
             bool pipelineReset() const { return m_resetPipeline; }
 
-            void videoTagsChanged(gint);
-            void audioTagsChanged(gint);
-            void notifyPlayerOfVideoTags();
-            void notifyPlayerOfAudioTags();
+            void videoChanged();
+            void audioChanged();
+            void notifyPlayerOfVideo();
+            void notifyPlayerOfAudio();
 
             unsigned decodedFrameCount() const;
             unsigned droppedFrameCount() const;
@@ -198,8 +189,8 @@
             guint m_muteTimerHandler;
             bool m_hasVideo;
             bool m_hasAudio;
-            guint m_audioTagsTimerHandler;
-            guint m_videoTagsTimerHandler;
+            guint m_audioTimerHandler;
+            guint m_videoTimerHandler;
             GstElement* m_webkitAudioSink;
     };
 }