f71123b31da2b32c54eb6ff28605146557f2843b
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / GStreamerUtilities.cpp
1 /*
2  *  Copyright (C) 2012, 2015, 2016 Igalia S.L
3  *  Copyright (C) 2015, 2016 Metrological Group B.V.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20
21 #include "config.h"
22
23 #if USE(GSTREAMER)
24 #include "GStreamerUtilities.h"
25
26 #include "GRefPtrGStreamer.h"
27 #include "IntSize.h"
28
29 #include <gst/audio/audio-info.h>
30 #include <gst/gst.h>
31 #include <wtf/MathExtras.h>
32 #include <wtf/glib/GUniquePtr.h>
33
34 #if ENABLE(VIDEO_TRACK) && USE(GSTREAMER_MPEGTS)
35 #define GST_USE_UNSTABLE_API
36 #include <gst/mpegts/mpegts.h>
37 #undef GST_USE_UNSTABLE_API
38 #endif
39
40 namespace WebCore {
41
42 const char* webkitGstMapInfoQuarkString = "webkit-gst-map-info";
43
44 GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate* staticPadTemplate, const gchar* name, GstPad* target)
45 {
46     GstPad* pad;
47     GstPadTemplate* padTemplate = gst_static_pad_template_get(staticPadTemplate);
48
49     if (target)
50         pad = gst_ghost_pad_new_from_template(name, target, padTemplate);
51     else
52         pad = gst_ghost_pad_new_no_target_from_template(name, padTemplate);
53
54     gst_object_unref(padTemplate);
55
56     return pad;
57 }
58
59 #if ENABLE(VIDEO)
60 bool getVideoSizeAndFormatFromCaps(GstCaps* caps, WebCore::IntSize& size, GstVideoFormat& format, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride)
61 {
62     GstVideoInfo info;
63
64     gst_video_info_init(&info);
65     if (!gst_video_info_from_caps(&info, caps))
66         return false;
67
68     format = GST_VIDEO_INFO_FORMAT(&info);
69     size.setWidth(GST_VIDEO_INFO_WIDTH(&info));
70     size.setHeight(GST_VIDEO_INFO_HEIGHT(&info));
71     pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info);
72     pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info);
73     stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0);
74
75     return true;
76 }
77
78 bool getSampleVideoInfo(GstSample* sample, GstVideoInfo& videoInfo)
79 {
80     if (!GST_IS_SAMPLE(sample))
81         return false;
82
83     GstCaps* caps = gst_sample_get_caps(sample);
84     if (!caps)
85         return false;
86
87     gst_video_info_init(&videoInfo);
88     if (!gst_video_info_from_caps(&videoInfo, caps))
89         return false;
90
91     return true;
92 }
93 #endif
94
95 GstBuffer* createGstBuffer(GstBuffer* buffer)
96 {
97     gsize bufferSize = gst_buffer_get_size(buffer);
98     GstBuffer* newBuffer = gst_buffer_new_and_alloc(bufferSize);
99
100     if (!newBuffer)
101         return 0;
102
103     gst_buffer_copy_into(newBuffer, buffer, static_cast<GstBufferCopyFlags>(GST_BUFFER_COPY_METADATA), 0, bufferSize);
104     return newBuffer;
105 }
106
107 GstBuffer* createGstBufferForData(const char* data, int length)
108 {
109     GstBuffer* buffer = gst_buffer_new_and_alloc(length);
110
111     gst_buffer_fill(buffer, 0, data, length);
112
113     return buffer;
114 }
115
116 char* getGstBufferDataPointer(GstBuffer* buffer)
117 {
118     GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
119     GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_get_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
120     return reinterpret_cast<char*>(mapInfo->data);
121 }
122
123 void mapGstBuffer(GstBuffer* buffer)
124 {
125     GstMapInfo* mapInfo = static_cast<GstMapInfo*>(fastMalloc(sizeof(GstMapInfo)));
126     if (!gst_buffer_map(buffer, mapInfo, GST_MAP_WRITE)) {
127         fastFree(mapInfo);
128         gst_buffer_unref(buffer);
129         return;
130     }
131
132     GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
133     gst_mini_object_set_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString), mapInfo, 0);
134 }
135
136 void unmapGstBuffer(GstBuffer* buffer)
137 {
138     GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
139     GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_steal_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
140
141     if (!mapInfo)
142         return;
143
144     gst_buffer_unmap(buffer, mapInfo);
145     fastFree(mapInfo);
146 }
147
148 bool initializeGStreamer()
149 {
150     if (gst_is_initialized())
151         return true;
152
153     GUniqueOutPtr<GError> error;
154     // FIXME: We should probably pass the arguments from the command line.
155     bool gstInitialized = gst_init_check(0, 0, &error.outPtr());
156     ASSERT_WITH_MESSAGE(gstInitialized, "GStreamer initialization failed: %s", error ? error->message : "unknown error occurred");
157
158 #if ENABLE(VIDEO_TRACK) && USE(GSTREAMER_MPEGTS)
159     if (gstInitialized)
160         gst_mpegts_initialize();
161 #endif
162
163     return gstInitialized;
164 }
165
166 unsigned getGstPlayFlag(const char* nick)
167 {
168     static GFlagsClass* flagsClass = static_cast<GFlagsClass*>(g_type_class_ref(g_type_from_name("GstPlayFlags")));
169     ASSERT(flagsClass);
170
171     GFlagsValue* flag = g_flags_get_value_by_nick(flagsClass, nick);
172     if (!flag)
173         return 0;
174
175     return flag->value;
176 }
177
178 GstClockTime toGstClockTime(float time)
179 {
180     // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to
181     // round the microseconds so no floating point precision is lost and we can perform an accurate seek.
182     float seconds;
183     float microSeconds = modff(time, &seconds) * 1000000;
184     GTimeVal timeValue;
185     timeValue.tv_sec = static_cast<glong>(seconds);
186     timeValue.tv_usec = static_cast<glong>(floor(microSeconds + 0.5));
187     return GST_TIMEVAL_TO_TIME(timeValue);
188 }
189
190 bool gstRegistryHasElementForMediaType(GList* elementFactories, const char* capsString)
191 {
192     GRefPtr<GstCaps> caps = adoptGRef(gst_caps_from_string(capsString));
193     GList* candidates = gst_element_factory_list_filter(elementFactories, caps.get(), GST_PAD_SINK, false);
194     bool result = candidates;
195
196     gst_plugin_feature_list_free(candidates);
197     return result;
198 }
199
200 #if GST_CHECK_VERSION(1, 5, 3) && (ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA))
201 GstElement* createGstDecryptor(const gchar* protectionSystem)
202 {
203     GstElement* decryptor = nullptr;
204     GList* decryptors = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECRYPTOR, GST_RANK_MARGINAL);
205
206     GST_TRACE("looking for decryptor for %s", protectionSystem);
207
208     for (GList* walk = decryptors; !decryptor && walk; walk = g_list_next(walk)) {
209         GstElementFactory* factory = reinterpret_cast<GstElementFactory*>(walk->data);
210
211         GST_TRACE("checking factory %s", GST_OBJECT_NAME(factory));
212
213         for (const GList* current = gst_element_factory_get_static_pad_templates(factory); current && !decryptor; current = g_list_next(current)) {
214             GstStaticPadTemplate* staticPadTemplate = static_cast<GstStaticPadTemplate*>(current->data);
215             GRefPtr<GstCaps> caps = adoptGRef(gst_static_pad_template_get_caps(staticPadTemplate));
216             unsigned length = gst_caps_get_size(caps.get());
217
218             GST_TRACE("factory %s caps has size %u", GST_OBJECT_NAME(factory), length);
219             for (unsigned i = 0; !decryptor && i < length; ++i) {
220                 GstStructure* structure = gst_caps_get_structure(caps.get(), i);
221                 GST_TRACE("checking structure %s", gst_structure_get_name(structure));
222                 if (gst_structure_has_field_typed(structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING)) {
223                     const gchar* sysId = gst_structure_get_string(structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD);
224                     GST_TRACE("structure %s has protection system %s", gst_structure_get_name(structure), sysId);
225                     if (!g_ascii_strcasecmp(protectionSystem, sysId)) {
226                         GST_DEBUG("found decryptor %s for %s", GST_OBJECT_NAME(factory), protectionSystem);
227                         decryptor = gst_element_factory_create(factory, nullptr);
228                         break;
229                     }
230                 }
231             }
232         }
233     }
234     gst_plugin_feature_list_free(decryptors);
235     GST_TRACE("returning decryptor %p", decryptor);
236     return decryptor;
237 }
238 #endif
239
240 }
241
242 #endif // USE(GSTREAMER)