6da49518bda11c470ca0ab47293f09120a4eb967
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / TrackPrivateBaseGStreamer.cpp
1 /*
2  * Copyright (C) 2013 Cable Television Laboratories, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK)
29
30 #include "TrackPrivateBaseGStreamer.h"
31
32 #include "GStreamerCommon.h"
33 #include "Logging.h"
34 #include "TrackPrivateBase.h"
35 #include <glib-object.h>
36 #include <gst/gst.h>
37 #include <gst/tag/tag.h>
38 #include <wtf/glib/GUniquePtr.h>
39 #include <wtf/text/CString.h>
40
41 GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
42 #define GST_CAT_DEFAULT webkit_media_player_debug
43
44 namespace WebCore {
45
46 TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer(TrackPrivateBase* owner, gint index, GRefPtr<GstPad> pad)
47     : m_notifier(MainThreadNotifier<MainThreadNotification>::create())
48     , m_index(index)
49     , m_pad(pad)
50     , m_owner(owner)
51 {
52     ASSERT(m_pad);
53
54     g_signal_connect_swapped(m_pad.get(), "notify::active", G_CALLBACK(activeChangedCallback), this);
55     g_signal_connect_swapped(m_pad.get(), "notify::tags", G_CALLBACK(tagsChangedCallback), this);
56
57     // We can't call notifyTrackOfTagsChanged() directly, because we need tagsChanged() to setup m_tags.
58     tagsChanged();
59 }
60
61 #if GST_CHECK_VERSION(1, 10, 0)
62 TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer(TrackPrivateBase* owner, gint index, GRefPtr<GstStream> stream)
63     : m_notifier(MainThreadNotifier<MainThreadNotification>::create())
64     , m_index(index)
65     , m_stream(stream)
66     , m_owner(owner)
67 {
68     ASSERT(m_stream);
69
70     // We can't call notifyTrackOfTagsChanged() directly, because we need tagsChanged() to setup m_tags.
71     tagsChanged();
72 }
73 #endif
74
75 TrackPrivateBaseGStreamer::~TrackPrivateBaseGStreamer()
76 {
77     disconnect();
78     m_notifier->invalidate();
79 }
80
81 void TrackPrivateBaseGStreamer::disconnect()
82 {
83     m_tags.clear();
84
85 #if GST_CHECK_VERSION(1, 10, 0)
86     if (m_stream)
87         m_stream.clear();
88 #endif
89
90     m_notifier->cancelPendingNotifications();
91
92     if (!m_pad)
93         return;
94
95     g_signal_handlers_disconnect_matched(m_pad.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
96     m_pad.clear();
97 }
98
99 void TrackPrivateBaseGStreamer::activeChangedCallback(TrackPrivateBaseGStreamer* track)
100 {
101     track->m_notifier->notify(MainThreadNotification::ActiveChanged, [track] { track->notifyTrackOfActiveChanged(); });
102 }
103
104 void TrackPrivateBaseGStreamer::tagsChangedCallback(TrackPrivateBaseGStreamer* track)
105 {
106     track->tagsChanged();
107 }
108
109 void TrackPrivateBaseGStreamer::tagsChanged()
110 {
111     GRefPtr<GstTagList> tags;
112     if (m_pad) {
113         if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_pad.get()), "tags"))
114             g_object_get(m_pad.get(), "tags", &tags.outPtr(), nullptr);
115         else
116             tags = adoptGRef(gst_tag_list_new_empty());
117     }
118 #if GST_CHECK_VERSION(1, 10, 0)
119     else if (m_stream)
120         tags = adoptGRef(gst_stream_get_tags(m_stream.get()));
121 #endif
122     else
123         tags = adoptGRef(gst_tag_list_new_empty());
124
125     GST_DEBUG("Inspecting track at index %d with tags: %" GST_PTR_FORMAT, m_index, tags.get());
126     {
127         LockHolder lock(m_tagMutex);
128         m_tags.swap(tags);
129     }
130
131     m_notifier->notify(MainThreadNotification::TagsChanged, [this] { notifyTrackOfTagsChanged(); });
132 }
133
134 void TrackPrivateBaseGStreamer::notifyTrackOfActiveChanged()
135 {
136     if (!m_pad)
137         return;
138
139     gboolean active = false;
140     if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_pad.get()), "active"))
141         g_object_get(m_pad.get(), "active", &active, nullptr);
142
143     setActive(active);
144 }
145
146 bool TrackPrivateBaseGStreamer::getLanguageCode(GstTagList* tags, AtomString& value)
147 {
148     String language;
149     if (getTag(tags, GST_TAG_LANGUAGE_CODE, language)) {
150         language = gst_tag_get_language_code_iso_639_1(language.utf8().data());
151         GST_DEBUG("Converted track %d's language code to %s.", m_index, language.utf8().data());
152         if (language != value) {
153             value = language;
154             return true;
155         }
156     }
157     return false;
158 }
159
160 template<class StringType>
161 bool TrackPrivateBaseGStreamer::getTag(GstTagList* tags, const gchar* tagName, StringType& value)
162 {
163     GUniqueOutPtr<gchar> tagValue;
164     if (gst_tag_list_get_string(tags, tagName, &tagValue.outPtr())) {
165         GST_DEBUG("Track %d got %s %s.", m_index, tagName, tagValue.get());
166         value = tagValue.get();
167         return true;
168     }
169     return false;
170 }
171
172 void TrackPrivateBaseGStreamer::notifyTrackOfTagsChanged()
173 {
174     TrackPrivateBaseClient* client = m_owner->client();
175
176     GRefPtr<GstTagList> tags;
177     {
178         LockHolder lock(m_tagMutex);
179         tags.swap(m_tags);
180     }
181
182     if (!tags)
183         return;
184
185     if (getTag(tags.get(), GST_TAG_TITLE, m_label) && client)
186         client->labelChanged(m_label);
187
188     AtomString language;
189     if (!getLanguageCode(tags.get(), language))
190         return;
191
192     if (language == m_language)
193         return;
194
195     m_language = language;
196     if (client)
197         client->languageChanged(m_language);
198 }
199
200 } // namespace WebCore
201
202 #endif // ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(VIDEO_TRACK)