hythmbox-2.98/backends/rb-encoder.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2006  James Livingston  <doclivingston@gmail.com>
  4  *
  5  *  This program is free software; you can redistribute it and/or modify
  6  *  it under the terms of the GNU General Public License as published by
  7  *  the Free Software Foundation; either version 2 of the License, or
  8  *  (at your option) any later version.
  9  *
 10  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 11  *  GStreamer plugins to be used and distributed together with GStreamer
 12  *  and Rhythmbox. This permission is above and beyond the permissions granted
 13  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 14  *  you may extend this exception to your version of the code, but you are not
 15  *  obligated to do so. If you do not wish to do so, delete this exception
 16  *  statement from your version.
 17  *
 18  *  This program is distributed in the hope that it will be useful,
 19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  *  GNU General Public License for more details.
 22  *
 23  *  You should have received a copy of the GNU General Public License
 24  *  along with this program; if not, write to the Free Software
 25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 26  *
 27  */
 28 
 29 #include <config.h>
 30 
 31 #include "rb-encoder.h"
 32 #include "rb-encoder-gst.h"
 33 #include "rb-marshal.h"
 34 
 35 /**
 36  * SECTION:rb-encoder
 37  * @short_description: audio transcoder interface
 38  *
 39  * The RBEncoder interface provides transcoding between audio formats based on
 40  * encoding profiles.  The encoder implementation operates asynchronously and
 41  * provides status updates in the form of signals emitted on the main thread.
 42  * A new encoder instance should be created for each file that is transcoded
 43  * or copied.
 44  */
 45 
 46 static void rb_encoder_factory_class_init (RBEncoderFactoryClass *klass);
 47 static void rb_encoder_factory_init       (RBEncoderFactory *encoder);
 48 
 49 /* Signals */
 50 enum {
 51 	PROGRESS,
 52 	COMPLETED,
 53 	PREPARE_SOURCE,		/* this is on RBEncoderFactory */
 54 	PREPARE_SINK,		/* this is on RBEncoderFactory */
 55 	LAST_SIGNAL
 56 };
 57 
 58 static guint signals[LAST_SIGNAL] = { 0 };
 59 
 60 static RBEncoderFactory *the_encoder_factory = NULL;
 61 static gsize encoder_factory_init = 0;
 62 
 63 G_DEFINE_TYPE(RBEncoderFactory, rb_encoder_factory, G_TYPE_OBJECT)
 64 
 65 static void
 66 rb_encoder_factory_init (RBEncoderFactory *factory)
 67 {
 68 }
 69 
 70 static void
 71 rb_encoder_factory_class_init (RBEncoderFactoryClass *klass)
 72 {
 73 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 74 
 75 	/**
 76 	 * RBEncoderFactory::prepare-source:
 77 	 * @factory: the #RBEncoderFactory instance
 78 	 * @uri: the URI for the source
 79 	 * @source: the source object (a GstElement in fact)
 80 	 *
 81 	 * Emitted when creating a source to read the specified URI.
 82 	 * Plugins can use this when just creating a GStreamer element from the URI
 83 	 * isn't enough.  Typically this happens when there's no way to pass device
 84 	 * information through the URI format.
 85 	 */
 86 	signals[PREPARE_SOURCE] =
 87 		g_signal_new ("prepare-source",
 88 			      G_OBJECT_CLASS_TYPE (object_class),
 89 			      G_SIGNAL_RUN_LAST,
 90 			      G_STRUCT_OFFSET (RBEncoderFactoryClass, prepare_source),
 91 			      NULL, NULL,
 92 			      rb_marshal_VOID__STRING_OBJECT,
 93 			      G_TYPE_NONE,
 94 			      2, G_TYPE_STRING, G_TYPE_OBJECT);
 95 	/**
 96 	 * RBEncoderFactory::prepare-sink:
 97 	 * @factory: the #RBEncoderFactory instance
 98 	 * @uri: the URI for the sink
 99 	 * @sink: the sink object (a GstElement in fact)
100 	 *
101 	 * Emitted when creating a sink to write to the specified URI.
102 	 * Plugins can use this when just creating a GStreamer element from the URI
103 	 * isn't enough.  Typically this happens when there's no way to pass device
104 	 * information through the URI format.
105 	 */
106 	signals[PREPARE_SINK] =
107 		g_signal_new ("prepare-sink",
108 			      G_OBJECT_CLASS_TYPE (object_class),
109 			      G_SIGNAL_RUN_LAST,
110 			      G_STRUCT_OFFSET (RBEncoderFactoryClass, prepare_sink),
111 			      NULL, NULL,
112 			      rb_marshal_VOID__STRING_OBJECT,
113 			      G_TYPE_NONE,
114 			      2, G_TYPE_STRING, G_TYPE_OBJECT);
115 }
116 
117 static void
118 rb_encoder_interface_init (RBEncoderIface *iface)
119 {
120 	/**
121 	 * RBEncoder::progress:
122 	 * @encoder: the #RBEncoder instance
123 	 * @fraction: progress as a fraction (0..1)
124 	 *
125 	 * Emitted regularly during the encoding process to provide progress updates.
126 	 */
127 	signals[PROGRESS] =
128 		g_signal_new ("progress",
129 			      G_TYPE_FROM_INTERFACE (iface),
130 			      G_SIGNAL_RUN_LAST,
131 			      G_STRUCT_OFFSET (RBEncoderIface, progress),
132 			      NULL, NULL,
133 			      g_cclosure_marshal_VOID__DOUBLE,
134 			      G_TYPE_NONE,
135 			      1, G_TYPE_DOUBLE);
136 	/**
137 	 * RBEncoder::completed:
138 	 * @encoder: the #RBEncoder instance
139 	 * @dest_size: size of the output file
140 	 * @mediatype: output media type
141 	 * @error: encoding error, or NULL if successful
142 	 * 
143 	 * Emitted when the encoding process is complete, or when a fatal error
144 	 * has occurred.  The destination file, if one exists,  will be closed
145 	 * and flushed to disk before this signal is emitted.
146 	 */
147 	signals[COMPLETED] =
148 		g_signal_new ("completed",
149 			      G_TYPE_FROM_INTERFACE (iface),
150 			      G_SIGNAL_RUN_LAST,
151 			      G_STRUCT_OFFSET (RBEncoderIface, completed),
152 			      NULL, NULL,
153 			      rb_marshal_VOID__UINT64_STRING_POINTER,
154 			      G_TYPE_NONE,
155 			      3, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_POINTER);
156 }
157 
158 GType
159 rb_encoder_get_type (void)
160 {
161 	static GType our_type = 0;
162 
163 	if (!our_type) {
164 		static const GTypeInfo our_info = {
165 			sizeof (RBEncoderIface),
166 			NULL,	/* base_init */
167 			NULL,	/* base_finalize */
168 			(GClassInitFunc)rb_encoder_interface_init,
169 			NULL,	/* class_finalize */
170 			NULL,	/* class_data */
171 			0,
172 			0,
173 			NULL
174 		};
175 
176 		our_type = g_type_register_static (G_TYPE_INTERFACE, "RBEncoder", &our_info, 0);
177 	}
178 
179 	return our_type;
180 }
181 
182 /**
183  * rb_encoder_factory_get:
184  *
185  * Returns the #RBEncoderFactory instance.
186  *
187  * Return value: (transfer none): the #RBEncoderFactory
188  */
189 RBEncoderFactory *
190 rb_encoder_factory_get ()
191 {
192 	if (g_once_init_enter (&encoder_factory_init)) {
193 		the_encoder_factory = g_object_new (RB_TYPE_ENCODER_FACTORY, NULL);
194 		g_once_init_leave (&encoder_factory_init, 1);
195 	}
196 
197 	return the_encoder_factory;
198 }
199 
200 /**
201  * rb_encoder_encode:
202  * @encoder: the #RBEncoder
203  * @entry: the #RhythmDBEntry to transcode
204  * @dest: destination file URI
205  * @overwrite: if %TRUE, overwrite @dest if it already exists
206  * @profile: encoding profile to use, or NULL to just copy
207  *
208  * Initiates encoding, transcoding to the specified profile if specified.
209  *
210  * Encoding and error reporting takes place asynchronously.  The caller should wait
211  * for the 'completed' signal which indicates it has either completed or failed.
212  */
213 void
214 rb_encoder_encode (RBEncoder *encoder,
215 		   RhythmDBEntry *entry,
216 		   const char *dest,
217 		   gboolean overwrite,
218 		   GstEncodingProfile *profile)
219 {
220 	RBEncoderIface *iface = RB_ENCODER_GET_IFACE (encoder);
221 
222 	iface->encode (encoder, entry, dest, overwrite, profile);
223 }
224 
225 /**
226  * rb_encoder_cancel:
227  * @encoder: a #RBEncoder
228  *
229  * Attempts to cancel any in progress encoding.  The encoder should
230  * delete the destination file, if it created one, and emit the
231  * 'completed' signal.
232  */
233 void
234 rb_encoder_cancel (RBEncoder *encoder)
235 {
236 	RBEncoderIface *iface = RB_ENCODER_GET_IFACE (encoder);
237 
238 	iface->cancel (encoder);
239 }
240 
241 /**
242  * rb_encoder_get_missing_plugins:
243  * @encoder: a #RBEncoder
244  * @profile: an encoding profile
245  * @details: (out callee-allocates): returns plugin installer detail strings
246  * @descriptions: (out callee-allocates): returns plugin descriptions
247  *
248  * Retrieves the plugin installer detail strings and descriptions
249  * for any missing plugins required to use the specified encoding profile.
250  *
251  * Return value: %TRUE if some detail strings are returned, %FALSE otherwise
252  */
253 gboolean
254 rb_encoder_get_missing_plugins (RBEncoder *encoder,
255 				GstEncodingProfile *profile,
256 				char ***details,
257 				char ***descriptions)
258 {
259 	RBEncoderIface *iface = RB_ENCODER_GET_IFACE (encoder);
260 	return iface->get_missing_plugins (encoder, profile, details, descriptions);
261 }
262 
263 /**
264  * rb_encoder_new:
265  *
266  * Creates a new #RBEncoder instance.
267  *
268  * Return value: (transfer full): the new #RBEncoder
269  */
270 RBEncoder*
271 rb_encoder_new (void)
272 {
273 	return rb_encoder_gst_new ();
274 }
275 
276 void
277 _rb_encoder_emit_progress (RBEncoder *encoder, double fraction)
278 {
279 	g_signal_emit (encoder, signals[PROGRESS], 0, fraction);
280 }
281 
282 void
283 _rb_encoder_emit_completed (RBEncoder *encoder, guint64 dest_size, const char *mediatype, GError *error)
284 {
285 	g_signal_emit (encoder, signals[COMPLETED], 0, dest_size, mediatype, error);
286 }
287 
288 void
289 _rb_encoder_emit_prepare_source (RBEncoder *encoder, const char *uri, GObject *source)
290 {
291 	g_signal_emit (rb_encoder_factory_get (), signals[PREPARE_SOURCE], 0, uri, source);
292 }
293 
294 void
295 _rb_encoder_emit_prepare_sink (RBEncoder *encoder, const char *uri, GObject *sink)
296 {
297 	g_signal_emit (rb_encoder_factory_get (), signals[PREPARE_SINK], 0, uri, sink);
298 }
299 
300 GQuark
301 rb_encoder_error_quark (void)
302 {
303 	static GQuark quark = 0;
304 	if (!quark)
305 		quark = g_quark_from_static_string ("rb_encoder_error");
306 
307 	return quark;
308 }
309 
310 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
311 
312 GType
313 rb_encoder_error_get_type (void)
314 {
315 	static GType etype = 0;
316 
317 	if (etype == 0)	{
318 		static const GEnumValue values[] = {
319 			ENUM_ENTRY (RB_ENCODER_ERROR_FORMAT_UNSUPPORTED, "format-unsupported"),
320 			ENUM_ENTRY (RB_ENCODER_ERROR_INTERNAL, "internal-error"),
321 			ENUM_ENTRY (RB_ENCODER_ERROR_FILE_ACCESS, "file-access-error"),
322 			ENUM_ENTRY (RB_ENCODER_ERROR_OUT_OF_SPACE, "out-of-space"),
323 			ENUM_ENTRY (RB_ENCODER_ERROR_DEST_READ_ONLY, "destination-read-only"),
324 			ENUM_ENTRY (RB_ENCODER_ERROR_DEST_EXISTS, "destination-exists"),
325 			{ 0, 0, 0 }
326 		};
327 
328 		etype = g_enum_register_static ("RBEncoderError", values);
329 	}
330 
331 	return etype;
332 }