~ubuntu-branches/ubuntu/lucid/webkit/lucid-updates

« back to all changes in this revision

Viewing changes to WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2010-02-04 19:30:57 UTC
  • mfrom: (1.2.8 upstream) (4.3.9 sid)
  • Revision ID: james.westby@ubuntu.com-20100204193057-d3018lm1fipb0703
* New upstream release
* debian/copyright:
- Updated with changes since 1.1.19.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
#include "CString.h"
31
31
#include "DataSourceGStreamer.h"
 
32
#include "Document.h"
 
33
#include "Frame.h"
 
34
#include "FrameView.h"
 
35
#include "GOwnPtrGtk.h"
32
36
#include "GraphicsContext.h"
33
37
#include "IntRect.h"
34
38
#include "KURL.h"
36
40
#include "MediaPlayer.h"
37
41
#include "NotImplemented.h"
38
42
#include "ScrollView.h"
 
43
#include "SecurityOrigin.h"
39
44
#include "TimeRanges.h"
40
45
#include "VideoSinkGStreamer.h"
41
46
#include "Widget.h"
46
51
#include <gst/video/video.h>
47
52
#include <limits>
48
53
#include <math.h>
 
54
#include <webkit/webkitwebview.h>
49
55
#include <wtf/gtk/GOwnPtr.h>
50
56
 
51
57
using namespace std;
59
65
    MediaPlayer::NetworkState error;
60
66
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
61
67
    gint percent = 0;
 
68
    bool issueError = true;
 
69
    bool attemptNextLocation = false;
 
70
 
 
71
    if (message->structure) {
 
72
        const gchar* messageTypeName = gst_structure_get_name(message->structure);
 
73
 
 
74
        // Redirect messages are sent from elements, like qtdemux, to
 
75
        // notify of the new location(s) of the media.
 
76
        if (!g_strcmp0(messageTypeName, "redirect")) {
 
77
            mp->mediaLocationChanged(message);
 
78
            return true;
 
79
        }
 
80
    }
62
81
 
63
82
    switch (GST_MESSAGE_TYPE(message)) {
64
83
    case GST_MESSAGE_ERROR:
 
84
        if (mp && mp->pipelineReset())
 
85
            break;
65
86
        gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
66
87
        LOG_VERBOSE(Media, "Error: %d, %s", err->code,  err->message);
67
88
 
72
93
            || err->code == GST_CORE_ERROR_MISSING_PLUGIN
73
94
            || err->code == GST_RESOURCE_ERROR_NOT_FOUND)
74
95
            error = MediaPlayer::FormatError;
75
 
        else if (err->domain == GST_STREAM_ERROR)
 
96
        else if (err->domain == GST_STREAM_ERROR) {
76
97
            error = MediaPlayer::DecodeError;
77
 
        else if (err->domain == GST_RESOURCE_ERROR)
 
98
            attemptNextLocation = true;
 
99
        } else if (err->domain == GST_RESOURCE_ERROR)
78
100
            error = MediaPlayer::NetworkError;
79
101
 
80
 
        if (mp)
81
 
            mp->loadingFailed(error);
 
102
        if (mp) {
 
103
            if (attemptNextLocation)
 
104
                issueError = !mp->loadNextLocation();
 
105
            if (issueError)
 
106
                mp->loadingFailed(error);
 
107
        }
82
108
        break;
83
109
    case GST_MESSAGE_EOS:
84
110
        LOG_VERBOSE(Media, "End of Stream");
103
129
    return true;
104
130
}
105
131
 
 
132
void mediaPlayerPrivateSourceChangedCallback(GObject *object, GParamSpec *pspec, gpointer data)
 
133
{
 
134
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
 
135
    GOwnPtr<GstElement> element;
 
136
 
 
137
    g_object_get(mp->m_playBin, "source", &element.outPtr(), NULL);
 
138
    gst_object_replace((GstObject**) &mp->m_source, (GstObject*) element.get());
 
139
 
 
140
    if (!element)
 
141
        return;
 
142
 
 
143
    GOwnPtr<char> location;
 
144
    g_object_get(element.get(), "location", &location.outPtr(), NULL);
 
145
 
 
146
    // Do injection only for elements dealing with uris.
 
147
    if (!gst_uri_is_valid(location.get()))
 
148
        return;
 
149
 
 
150
    GOwnPtr<SoupURI> uri(soup_uri_new(location.get()));
 
151
 
 
152
    // Do injection only for http(s) uris.
 
153
    if (!SOUP_URI_VALID_FOR_HTTP(uri))
 
154
        return;
 
155
 
 
156
    // Let Apple web servers know we want to access their nice movie trailers.
 
157
    if (g_str_equal(uri->host, "movies.apple.com"))
 
158
        g_object_set(element.get(), "user-agent", "Quicktime/7.2.0", NULL);
 
159
 
 
160
    // Set the HTTP referer.
 
161
    Frame* frame = mp->m_player->frameView() ? mp->m_player->frameView()->frame() : 0;
 
162
    Document* document = frame ? frame->document() : 0;
 
163
    if (document) {
 
164
        GstStructure* extraHeaders = gst_structure_new("extra-headers",
 
165
                                                       "Referer", G_TYPE_STRING,
 
166
                                                       document->documentURI().utf8().data(), 0);
 
167
        g_object_set(element.get(), "extra-headers", extraHeaders, NULL);
 
168
        gst_structure_free(extraHeaders);
 
169
    }
 
170
 
 
171
    // Deal with the cookies from now on.
 
172
    GParamSpec* cookiesParamSpec = g_object_class_find_property(G_OBJECT_GET_CLASS(element.get()), "cookies");
 
173
 
 
174
    // First check if the source element has a cookies property
 
175
    // of the format we expect
 
176
    if (!cookiesParamSpec || cookiesParamSpec->value_type != G_TYPE_STRV)
 
177
        return;
 
178
 
 
179
    // Then get the cookies for the URI and set them
 
180
    SoupSession* session = webkit_get_default_session();
 
181
    SoupSessionFeature* cookieJarFeature = soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR);
 
182
    if (!cookieJarFeature)
 
183
        return;
 
184
 
 
185
    SoupCookieJar* cookieJar = SOUP_COOKIE_JAR(cookieJarFeature);
 
186
    GOwnPtr<char> cookies(soup_cookie_jar_get_cookies(cookieJar, uri.get(), FALSE));
 
187
    char* cookiesStrv[] = {cookies.get(), 0};
 
188
    g_object_set(element.get(), "cookies", cookiesStrv, NULL);
 
189
}
 
190
 
106
191
void mediaPlayerPrivateVolumeChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
107
192
{
108
 
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
109
 
    mp->volumeChanged();
110
 
}
111
 
 
112
 
gboolean notifyVolumeIdleCallback(MediaPlayer* mp)
113
 
{
114
 
    mp->volumeChanged();
 
193
    // This is called when playbin receives the notify::volume signal.
 
194
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
 
195
    mp->volumeChanged();
 
196
}
 
197
 
 
198
gboolean notifyVolumeIdleCallback(gpointer data)
 
199
{
 
200
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
 
201
    mp->volumeChangedCallback();
 
202
    return FALSE;
 
203
}
 
204
 
 
205
void mediaPlayerPrivateMuteChangedCallback(GObject *element, GParamSpec *pspec, gpointer data)
 
206
{
 
207
    // This is called when playbin receives the notify::mute signal.
 
208
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
 
209
    mp->muteChanged();
 
210
}
 
211
 
 
212
gboolean notifyMuteIdleCallback(gpointer data)
 
213
{
 
214
    MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
 
215
    mp->muteChangedCallback();
115
216
    return FALSE;
116
217
}
117
218
 
208
309
    , m_isStreaming(false)
209
310
    , m_size(IntSize())
210
311
    , m_buffer(0)
 
312
    , m_mediaLocations(0)
 
313
    , m_mediaLocationCurrentIndex(0)
 
314
    , m_resetPipeline(false)
211
315
    , m_paused(true)
212
316
    , m_seeking(false)
213
317
    , m_playbackRate(1)
214
318
    , m_errorOccured(false)
215
 
    , m_volumeIdleId(-1)
 
319
    , m_volumeIdleId(0)
 
320
    , m_mediaDuration(0.0)
 
321
    , m_muteIdleId(0)
216
322
{
217
323
    doGstInit();
218
324
}
221
327
{
222
328
    if (m_volumeIdleId) {
223
329
        g_source_remove(m_volumeIdleId);
224
 
        m_volumeIdleId = -1;
 
330
        m_volumeIdleId = 0;
 
331
    }
 
332
 
 
333
    if (m_muteIdleId) {
 
334
        g_source_remove(m_muteIdleId);
 
335
        m_muteIdleId = 0;
225
336
    }
226
337
 
227
338
    if (m_buffer)
228
339
        gst_buffer_unref(m_buffer);
229
340
    m_buffer = 0;
230
341
 
 
342
    if (m_mediaLocations) {
 
343
        gst_structure_free(m_mediaLocations);
 
344
        m_mediaLocations = 0;
 
345
    }
 
346
 
 
347
    if (m_source) {
 
348
        gst_object_unref(m_source);
 
349
        m_source = 0;
 
350
    }
 
351
 
231
352
    if (m_playBin) {
232
353
        gst_element_set_state(m_playBin, GST_STATE_NULL);
233
354
        gst_object_unref(GST_OBJECT(m_playBin));
299
420
    if (m_errorOccured)
300
421
        return 0.0;
301
422
 
 
423
    if (m_mediaDuration)
 
424
        return m_mediaDuration;
 
425
 
302
426
    GstFormat timeFormat = GST_FORMAT_TIME;
303
427
    gint64 timeLength = 0;
304
428
 
357
481
    }
358
482
}
359
483
 
360
 
void MediaPlayerPrivate::setEndTime(float time)
361
 
{
362
 
    notImplemented();
363
 
}
364
 
 
365
484
void MediaPlayerPrivate::startEndPointTimerIfNeeded()
366
485
{
367
486
    notImplemented();
444
563
    g_object_set(m_playBin, "volume", static_cast<double>(volume), NULL);
445
564
}
446
565
 
 
566
void MediaPlayerPrivate::volumeChangedCallback()
 
567
{
 
568
    double volume;
 
569
    g_object_get(m_playBin, "volume", &volume, NULL);
 
570
    m_player->volumeChanged(static_cast<float>(volume));
 
571
}
 
572
 
447
573
void MediaPlayerPrivate::volumeChanged()
448
574
{
449
 
    if (m_volumeIdleId) {
 
575
    if (m_volumeIdleId)
450
576
        g_source_remove(m_volumeIdleId);
451
 
        m_volumeIdleId = -1;
452
 
    }
453
 
    m_volumeIdleId = g_idle_add((GSourceFunc) notifyVolumeIdleCallback, m_player);
 
577
    m_volumeIdleId = g_idle_add((GSourceFunc) notifyVolumeIdleCallback, this);
454
578
}
455
579
 
456
 
 
457
580
void MediaPlayerPrivate::setRate(float rate)
458
581
{
459
582
    // Avoid useless playback rate update.
507
630
        g_object_set(m_playBin, "mute", mute, NULL);
508
631
}
509
632
 
510
 
int MediaPlayerPrivate::dataRate() const
511
 
{
512
 
    notImplemented();
513
 
    return 1;
514
 
}
515
 
 
516
633
MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
517
634
{
518
635
    return m_networkState;
570
687
    return 1; // totalBytes() * maxTime / dur;
571
688
}
572
689
 
573
 
bool MediaPlayerPrivate::totalBytesKnown() const
574
 
{
575
 
    LOG_VERBOSE(Media, "totalBytesKnown");
576
 
    return totalBytes() > 0;
577
 
}
578
 
 
579
690
unsigned MediaPlayerPrivate::totalBytes() const
580
691
{
581
692
    LOG_VERBOSE(Media, "totalBytes");
628
739
            gst_element_state_get_name(state),
629
740
            gst_element_state_get_name(pending));
630
741
 
 
742
        m_resetPipeline = state <= GST_STATE_READY;
 
743
 
631
744
        if (state == GST_STATE_READY)
632
745
            m_readyState = MediaPlayer::HaveNothing;
633
746
        else if (state == GST_STATE_PAUSED)
636
749
        if (state == GST_STATE_PLAYING) {
637
750
            m_readyState = MediaPlayer::HaveEnoughData;
638
751
            m_paused = false;
 
752
            if (!m_mediaDuration) {
 
753
                float newDuration = duration();
 
754
                if (!isinf(newDuration))
 
755
                    m_mediaDuration = newDuration;
 
756
            }
639
757
        } else
640
758
            m_paused = true;
641
759
 
650
768
        }
651
769
 
652
770
        m_networkState = MediaPlayer::Loaded;
653
 
 
654
 
        g_object_get(m_playBin, "source", &m_source, NULL);
655
 
        if (!m_source)
656
 
            LOG_VERBOSE(Media, "m_source is 0");
657
771
        break;
658
772
    case GST_STATE_CHANGE_ASYNC:
659
773
        LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
702
816
    }
703
817
}
704
818
 
 
819
void MediaPlayerPrivate::mediaLocationChanged(GstMessage* message)
 
820
{
 
821
    if (m_mediaLocations)
 
822
        gst_structure_free(m_mediaLocations);
 
823
 
 
824
    if (message->structure) {
 
825
        // This structure can contain:
 
826
        // - both a new-location string and embedded locations structure
 
827
        // - or only a new-location string.
 
828
        m_mediaLocations = gst_structure_copy(message->structure);
 
829
        const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
 
830
 
 
831
        if (locations)
 
832
            m_mediaLocationCurrentIndex = gst_value_list_get_size(locations) -1;
 
833
 
 
834
        loadNextLocation();
 
835
    }
 
836
}
 
837
 
 
838
bool MediaPlayerPrivate::loadNextLocation()
 
839
{
 
840
    if (!m_mediaLocations)
 
841
        return false;
 
842
 
 
843
    const GValue* locations = gst_structure_get_value(m_mediaLocations, "locations");
 
844
    const gchar* newLocation = 0;
 
845
 
 
846
    if (!locations) {
 
847
        // Fallback on new-location string.
 
848
        newLocation = gst_structure_get_string(m_mediaLocations, "new-location");
 
849
        if (!newLocation)
 
850
            return false;
 
851
    }
 
852
 
 
853
    if (!newLocation) {
 
854
        if (m_mediaLocationCurrentIndex < 0) {
 
855
            m_mediaLocations = 0;
 
856
            return false;
 
857
        }
 
858
 
 
859
        const GValue* location = gst_value_list_get_value(locations,
 
860
                                                          m_mediaLocationCurrentIndex);
 
861
        const GstStructure* structure = gst_value_get_structure(location);
 
862
 
 
863
        if (!structure) {
 
864
            m_mediaLocationCurrentIndex--;
 
865
            return false;
 
866
        }
 
867
 
 
868
        newLocation = gst_structure_get_string(structure, "new-location");
 
869
    }
 
870
 
 
871
    if (newLocation) {
 
872
        // Found a candidate. new-location is not always an absolute url
 
873
        // though. We need to take the base of the current url and
 
874
        // append the value of new-location to it.
 
875
 
 
876
        gchar* currentLocation = 0;
 
877
        g_object_get(m_playBin, "uri", &currentLocation, NULL);
 
878
 
 
879
        KURL currentUrl(KURL(), currentLocation);
 
880
        g_free(currentLocation);
 
881
 
 
882
        KURL newUrl;
 
883
 
 
884
        if (gst_uri_is_valid(newLocation))
 
885
            newUrl = KURL(KURL(), newLocation);
 
886
        else
 
887
            newUrl = KURL(KURL(), currentUrl.baseAsString() + newLocation);
 
888
 
 
889
        RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(currentUrl);
 
890
        if (securityOrigin->canRequest(newUrl)) {
 
891
            LOG_VERBOSE(Media, "New media url: %s", newUrl.string().utf8().data());
 
892
 
 
893
            // Reset player states.
 
894
            m_networkState = MediaPlayer::Loading;
 
895
            m_player->networkStateChanged();
 
896
            m_readyState = MediaPlayer::HaveNothing;
 
897
            m_player->readyStateChanged();
 
898
 
 
899
            // Reset pipeline state.
 
900
            m_resetPipeline = true;
 
901
            gst_element_set_state(m_playBin, GST_STATE_READY);
 
902
 
 
903
            GstState state;
 
904
            gst_element_get_state(m_playBin, &state, 0, 0);
 
905
            if (state <= GST_STATE_READY) {
 
906
                // Set the new uri and start playing.
 
907
                g_object_set(m_playBin, "uri", newUrl.string().utf8().data(), NULL);
 
908
                gst_element_set_state(m_playBin, GST_STATE_PLAYING);
 
909
                return true;
 
910
            }
 
911
        }
 
912
    }
 
913
    m_mediaLocationCurrentIndex--;
 
914
    return false;
 
915
 
 
916
}
 
917
 
705
918
void MediaPlayerPrivate::loadStateChanged()
706
919
{
707
920
    updateStates();
720
933
 
721
934
void MediaPlayerPrivate::didEnd()
722
935
{
 
936
    // EOS was reached but in case of reverse playback the position is
 
937
    // not always 0. So to not confuse the HTMLMediaElement we
 
938
    // synchronize position and duration values.
 
939
    float now = currentTime();
 
940
    if (now > 0)
 
941
        m_mediaDuration = now;
 
942
    gst_element_set_state(m_playBin, GST_STATE_PAUSED);
 
943
 
723
944
    timeChanged();
724
945
}
725
946
 
726
947
void MediaPlayerPrivate::durationChanged()
727
948
{
 
949
    // Reset cached media duration
 
950
    m_mediaDuration = 0;
 
951
 
 
952
    // And re-cache it if possible.
 
953
    float newDuration = duration();
 
954
    if (!isinf(newDuration))
 
955
        m_mediaDuration = newDuration;
 
956
 
728
957
    m_player->durationChanged();
729
958
}
730
959
 
 
960
bool MediaPlayerPrivate::supportsMuting() const
 
961
{
 
962
    return true;
 
963
}
 
964
 
 
965
void MediaPlayerPrivate::setMuted(bool muted)
 
966
{
 
967
    if (!m_playBin)
 
968
        return;
 
969
 
 
970
    g_object_set(m_playBin, "mute", muted, NULL);
 
971
}
 
972
 
 
973
void MediaPlayerPrivate::muteChangedCallback()
 
974
{
 
975
    gboolean muted;
 
976
    g_object_get(m_playBin, "mute", &muted, NULL);
 
977
    m_player->muteChanged(static_cast<bool>(muted));
 
978
}
 
979
 
 
980
void MediaPlayerPrivate::muteChanged()
 
981
{
 
982
    if (m_muteIdleId)
 
983
        g_source_remove(m_muteIdleId);
 
984
 
 
985
    m_muteIdleId = g_idle_add((GSourceFunc) notifyMuteIdleCallback, this);
 
986
}
 
987
 
731
988
void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error)
732
989
{
733
990
    m_errorOccured = true;
945
1202
    g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
946
1203
 
947
1204
    g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
 
1205
    g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
 
1206
    g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
948
1207
 
949
1208
    m_videoSink = webkit_video_sink_new();
950
1209