1 // GstUtil.cpp: Generalized Gstreamer utilities for pipeline configuration.
2 //
3 // Copyright (C) 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20
21
22 #ifdef HAVE_CONFIG_H
23 #include "gnashconfig.h"
24 #endif
25
26 #include <sstream>
27 #include <vector>
28
29 #include "GstUtil.h"
30 #include "log.h"
31 #include "GnashException.h"
32
33 #include "swfdec_codec_gst.h"
34
35 #ifdef HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
36 #include <gst/pbutils/pbutils.h>
37 #include <gst/pbutils/missing-plugins.h>
38 #include <gst/pbutils/install-plugins.h>
39 #endif // HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
40
41
42 namespace gnash {
43 namespace media {
44 namespace gst {
45
get_audiosink_element()46 GstElement* GstUtil::get_audiosink_element()
47 {
48 //MUST be static to get a numbered name for each non-trivial pipeline created
49 static int numGnashRcSinks = 0;
50
51 /*These MAY be static for CPU optimization
52 *But, the memory cost at global scope is probably
53 *worse overall than the CPU cost at initialization time.*/
54 const std::string GNASHRCSINK = "gnashrcsink";
55 const std::string sAudioSink =
56 RcInitFile::getDefaultInstance().getGstAudioSink();
57
58 //Can't be static. One of these must be created for each call
59 GstElement* element;
60
61 if(sAudioSink.find('!') != std::string::npos) //Found a non-trivial pipeline - bin it
62 {
63 element = gst_parse_bin_from_description(sAudioSink.c_str(), true, nullptr);
64 if(element != nullptr)
65 {
66 std::ostringstream o;
67 o << numGnashRcSinks++;
68 gst_element_set_name(element, (GNASHRCSINK + o.str()).c_str());
69 }
70 }
71 else //Found a trivial pipeline that doesn't need a bin
72 {
73 element = gst_element_factory_make(sAudioSink.c_str(), nullptr);
74 }
75
76 if(!element)
77 {
78 log_debug(_("Unable to retrieve a valid audio sink from ~/.gnashrc"));
79
80 element = gst_element_factory_make("autoaudiosink", nullptr);
81
82 if(!element)
83 {
84 log_debug(_("Unable to retrieve a valid audio sink from autoaudiosink"));
85
86 element = gst_element_factory_make("gconfaudiosink", nullptr);
87
88 if(!element)
89 log_error(_("Unable to retrieve a valid audio sink from gconfaudiosink\n%s"),
90 _("Sink search exhausted: you won't be able to hear sound!"));
91 }
92 }
93
94 if(element)
95 {
96 log_debug(_("Got a non-NULL audio sink; its wrapper name is: %s"), _(GST_ELEMENT_NAME(element)));
97 }
98
99 return element;
100 }
101
102 /**
103 This function is not thread-safe.
104 **/
105 bool
check_missing_plugins(GstCaps * caps,HostInterface * eventHandler)106 GstUtil::check_missing_plugins(GstCaps* caps, HostInterface* eventHandler)
107 {
108 GstElementFactory * factory = swfdec_gst_get_element_factory(caps);
109
110 if (factory) {
111 gst_object_unref(factory);
112 return true;
113 }
114
115 #ifdef HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
116
117 if(!eventHandler){
118 throw new GnashException("GstUtil::check_missing_plugins was not given a HostInterface");
119 }
120
121 if (GstUtil::no_plugin_install){
122 return false;
123 }
124
125 gst_pb_utils_init();
126
127
128 if (!gst_install_plugins_supported()) {
129 log_error(_("Missing plugin, but plugin installing not supported."
130 " Will try anyway, but expect failure."));
131 }
132
133 char* detail = gst_missing_decoder_installer_detail_new(caps);
134 if (!detail) {
135 log_error(_("Missing plugin, but failed to convert it to gst"
136 " missing plugin detail."));
137 return false;
138 }
139
140 char* details[] = { detail, nullptr };
141
142 std::vector<void*> * callback_data = new std::vector<void*>;
143 callback_data->push_back(detail);
144 callback_data->push_back(eventHandler);
145
146 GstInstallPluginsReturn ret = gst_install_plugins_async(details, nullptr, GstUtil::plugin_installer_return, callback_data);
147
148 if (ret == GST_INSTALL_PLUGINS_STARTED_OK) {
149 eventHandler->call(HostMessage(HostMessage::EXTERNALINTERFACE_STOPPLAY));
150 return true;
151 } else {
152 log_error(_("gst_install_plugins_async failed. Please report."));
153 g_free(detail);
154 return false;
155 }
156
157 #else
158 log_error(_("Missing plugin, but automatic plugin installation not "
159 "available."));
160 return false;
161 #endif // end of HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
162
163 }
164
165 #ifdef HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
166
167 // static
168 bool GstUtil::no_plugin_install = false;
169
170 // Helper function for plugin_installer_return below.
171 // Called when all or some plugins were successfully installed
172 // static
173 void
plugin_success_dialog(const char * success_msg,const char * fail_msg,HostInterface * eventHandler)174 GstUtil::plugin_success_dialog(const char* success_msg,
175 const char* fail_msg,
176 HostInterface* eventHandler)
177 {
178 if (! gst_update_registry()) {
179 log_error(_("gst_update_registry failed. You'll need to "
180 "restart Gnash to use the new plugins."));
181 eventHandler->call(HostMessage(HostMessage::NOTIFY_ERROR,
182 std::string(fail_msg)));
183 GstUtil::no_plugin_install = true;
184 } else {
185 bool restart = boost::any_cast<bool>(eventHandler->call(HostMessage(HostMessage::QUERY,
186 std::string(success_msg))));
187 if(restart){
188 eventHandler->call(HostMessage(HostMessage::EXTERNALINTERFACE_REWIND));
189 }
190 }
191 }
192
193 // Helper function for plugin_installer_return below.
194 // Called when there is an error during plugin installation
195 // static
196 void
plugin_fail_dialog(const char * fail_msg,HostInterface * eventHandler)197 GstUtil::plugin_fail_dialog(const char* fail_msg,
198 HostInterface* eventHandler)
199 {
200 GstUtil::no_plugin_install = boost::any_cast<bool>(eventHandler->call(HostMessage(HostMessage::QUERY,
201 std::string(fail_msg)
202 + std::string(_(" Do you wish to block any further attempts at plugin installation?")))));
203 }
204
205
206
207 // Callback function for use by the plugin installer
208 void
plugin_installer_return(GstInstallPluginsReturn result,gpointer user_data)209 GstUtil::plugin_installer_return(GstInstallPluginsReturn result,
210 gpointer user_data)
211 {
212 std::vector<void*> * v((std::vector<void*> *) (user_data));
213 HostInterface* eventHandler = (HostInterface*) (v->at(1));
214 char* detail = (char*) v->at(0);
215
216 g_free(detail);
217
218 if(!eventHandler){
219 throw new GnashException("plugin_installer_return was not given a HostInterface");
220 }
221 switch(result) {
222 case GST_INSTALL_PLUGINS_SUCCESS:
223 plugin_success_dialog(_("Plugin installation succeeded. Do you wish to restart the movie from the beginning?"),_("Plugin installation succeeded, but could not be registered by Gnash. You will need to restart Gnash to see all content in this file."), eventHandler);
224 break;
225 case GST_INSTALL_PLUGINS_NOT_FOUND:
226 plugin_fail_dialog(_("A plugin needed for playing this file was not found. You may still play the file, but some content may not be shown."), eventHandler);
227 break;
228 case GST_INSTALL_PLUGINS_ERROR:
229 plugin_fail_dialog(_("There was an error during installation of a plugin needed for playing this file. You may still play the file, but some content may not be shown."), eventHandler);
230 break;
231 case GST_INSTALL_PLUGINS_PARTIAL_SUCCESS:
232 plugin_fail_dialog(_("Only some of the plugins needed to see this movie could be installed. To see all content here you will need to install these."), eventHandler);
233 plugin_success_dialog(_("Do you wish to restart the movie from the beginning?"),_("Some plugins were installed, but could not be registered by Gnash. You will need to restart gnash to see more content in this file. To see all content in this file you also need to install the remaining plugins"), eventHandler);
234 break;
235 case GST_INSTALL_PLUGINS_USER_ABORT:
236 plugin_fail_dialog("", eventHandler);
237 break;
238 default:
239 throw new GnashException("Gst plugin installer returned unrecognized error code.");
240 }
241 eventHandler->call(HostMessage(HostMessage::EXTERNALINTERFACE_PLAY));
242 g_free(v);
243 return;
244 }
245
246 #endif // end of HAVE_GST_PBUTILS_INSTALL_PLUGINS_H
247
248 } // gnash.media.gst namespace
249 } // gnash.media namespace
250 } // namespace gnash
251
252 // Local Variables:
253 // mode: C++
254 // End:
255
256