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 }