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