~ubuntu-branches/ubuntu/trusty/banshee/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/Initial-port-to-GStreamer-1.0.patch/libbanshee/banshee-transcoder.c

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2012-11-30 18:17:37 UTC
  • mfrom: (6.3.28 experimental)
  • Revision ID: package-import@ubuntu.com-20121130181737-67acktvo9zy57coc
Tags: 2.6.0-3ubuntu1
* [8bf15b5] Merge from Debian Experimental, remaining changes:
  - Enable and recommend SoundMenu and Disable NotificationArea by default
  - Disable boo and karma extensions
  - Move desktop file for Meego UI to /usr/share/une/applications
  - Change the url for the Amazon store redirector
  - [9b356d6] Add workaround for set_Height exception.
  - [ccbcbbd] Make Banshee translatable in Launchpad
  - [2094ee5] Bump libgpod build-dep version to 0.8.2-7~
    This is to pick up the arch-specific libgpod.dll binary (LP: #1070631)
  - [03c8cad] Set debian-branch to ubuntu/raring

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// banshee-transcoder.c
 
3
//
 
4
// Author:
 
5
//   Aaron Bockover <abockover@novell.com>
 
6
//
 
7
// Copyright (C) 2005-2008 Novell, Inc.
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
//
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
//
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
#include <gst/gst.h>
 
30
#include <sys/stat.h>
 
31
#include <sys/types.h>
 
32
#include <glib.h>
 
33
#include <glib/gi18n.h>
 
34
#include <glib/gstdio.h>
 
35
 
 
36
typedef struct GstTranscoder GstTranscoder;
 
37
 
 
38
typedef void (* GstTranscoderProgressCallback) (GstTranscoder *transcoder, gdouble progress);
 
39
typedef void (* GstTranscoderFinishedCallback) (GstTranscoder *transcoder);
 
40
typedef void (* GstTranscoderErrorCallback) (GstTranscoder *transcoder, const gchar *error, const gchar *debug);
 
41
 
 
42
struct GstTranscoder {
 
43
    gboolean is_transcoding;
 
44
    guint iterate_timeout_id;
 
45
    GstElement *pipeline;
 
46
    GstElement *sink_bin;
 
47
    gchar *output_uri;
 
48
    GstTranscoderProgressCallback progress_cb;
 
49
    GstTranscoderFinishedCallback finished_cb;
 
50
    GstTranscoderErrorCallback error_cb;
 
51
};
 
52
 
 
53
// private methods
 
54
 
 
55
static void
 
56
gst_transcoder_raise_error(GstTranscoder *transcoder, const gchar *error, const gchar *debug)
 
57
{
 
58
    g_return_if_fail(transcoder != NULL);
 
59
    g_return_if_fail(transcoder->error_cb != NULL);
 
60
    
 
61
    transcoder->error_cb(transcoder, error, debug);
 
62
}
 
63
 
 
64
static gboolean
 
65
gst_transcoder_iterate_timeout(GstTranscoder *transcoder)
 
66
{
 
67
    GstFormat format = GST_FORMAT_TIME;
 
68
    gint64 position;
 
69
    gint64 duration;
 
70
 
 
71
    g_return_val_if_fail(transcoder != NULL, FALSE);
 
72
 
 
73
    if(!gst_element_query_duration(transcoder->pipeline, &format, &duration) ||
 
74
        !gst_element_query_position(transcoder->sink_bin, &format, &position)) {
 
75
        return TRUE;
 
76
    }
 
77
 
 
78
    if(transcoder->progress_cb != NULL) {
 
79
        transcoder->progress_cb(transcoder, (double)position / (double)duration);
 
80
    }
 
81
    
 
82
    return TRUE;
 
83
}
 
84
 
 
85
static void
 
86
gst_transcoder_start_iterate_timeout(GstTranscoder *transcoder)
 
87
{
 
88
    g_return_if_fail(transcoder != NULL);
 
89
 
 
90
    if(transcoder->iterate_timeout_id != 0) {
 
91
        return;
 
92
    }
 
93
    
 
94
    transcoder->iterate_timeout_id = g_timeout_add(200, 
 
95
        (GSourceFunc)gst_transcoder_iterate_timeout, transcoder);
 
96
}
 
97
 
 
98
static void
 
99
gst_transcoder_stop_iterate_timeout(GstTranscoder *transcoder)
 
100
{
 
101
    g_return_if_fail(transcoder != NULL);
 
102
    
 
103
    if(transcoder->iterate_timeout_id == 0) {
 
104
        return;
 
105
    }
 
106
    
 
107
    g_source_remove(transcoder->iterate_timeout_id);
 
108
    transcoder->iterate_timeout_id = 0;
 
109
}
 
110
 
 
111
static gboolean
 
112
gst_transcoder_bus_callback(GstBus *bus, GstMessage *message, gpointer data)
 
113
{
 
114
    GstTranscoder *transcoder = (GstTranscoder *)data;
 
115
 
 
116
    g_return_val_if_fail(transcoder != NULL, FALSE);
 
117
 
 
118
    switch(GST_MESSAGE_TYPE(message)) {
 
119
        case GST_MESSAGE_ERROR: {
 
120
            GError *error;
 
121
            gchar *debug;
 
122
            
 
123
            transcoder->is_transcoding = FALSE;
 
124
            gst_transcoder_stop_iterate_timeout(transcoder);
 
125
            
 
126
            if(transcoder->error_cb != NULL) {
 
127
                gst_message_parse_error(message, &error, &debug);
 
128
                gst_transcoder_raise_error(transcoder, error->message, debug);
 
129
                g_error_free(error);
 
130
                g_free(debug);
 
131
            }
 
132
            
 
133
            break;
 
134
        }        
 
135
        case GST_MESSAGE_EOS:
 
136
            gst_element_set_state(GST_ELEMENT(transcoder->pipeline), GST_STATE_NULL);
 
137
            g_object_unref(G_OBJECT(transcoder->pipeline));
 
138
            transcoder->pipeline = NULL;
 
139
            
 
140
            transcoder->is_transcoding = FALSE;
 
141
            gst_transcoder_stop_iterate_timeout(transcoder);
 
142
 
 
143
            /*
 
144
             FIXME: Replace with regular stat
 
145
             GnomeVFSFileInfo fileinfo;
 
146
            if(gnome_vfs_get_file_info(transcoder->output_uri, &fileinfo, 
 
147
                GNOME_VFS_FILE_INFO_DEFAULT) == GNOME_VFS_OK) {
 
148
                if(fileinfo.size < 100) {
 
149
                    gst_transcoder_raise_error(transcoder, 
 
150
                        _("No decoder could be found for source format."), NULL);
 
151
                    g_remove(transcoder->output_uri);
 
152
                    break;
 
153
                }
 
154
            } else {
 
155
                gst_transcoder_raise_error(transcoder, _("Could not stat encoded file"), NULL);
 
156
                break;
 
157
            }*/
 
158
            
 
159
            if(transcoder->finished_cb != NULL) {
 
160
                transcoder->finished_cb(transcoder);
 
161
            }
 
162
            break;
 
163
        default:
 
164
            break;
 
165
    }
 
166
    
 
167
    return TRUE;
 
168
}
 
169
 
 
170
static GstElement *
 
171
gst_transcoder_build_encoder(const gchar *encoder_pipeline)
 
172
{
 
173
    GstElement *encoder = NULL;
 
174
    gchar *pipeline;
 
175
    GError *error = NULL;
 
176
    
 
177
    pipeline = g_strdup_printf("%s", encoder_pipeline); 
 
178
    encoder = gst_parse_bin_from_description(pipeline, TRUE, &error);
 
179
    g_free(pipeline);
 
180
    
 
181
    if(error != NULL) {
 
182
        return NULL;
 
183
    }
 
184
    
 
185
    return encoder;
 
186
}    
 
187
 
 
188
static void
 
189
gst_transcoder_new_decoded_pad(GstElement *decodebin, GstPad *pad, 
 
190
    gboolean last, gpointer data)
 
191
{
 
192
    GstCaps *caps;
 
193
    GstStructure *str;
 
194
    GstPad *audiopad;
 
195
    GstTranscoder *transcoder = (GstTranscoder *)data;
 
196
 
 
197
    g_return_if_fail(transcoder != NULL);
 
198
 
 
199
    audiopad = gst_element_get_pad(transcoder->sink_bin, "sink");
 
200
    
 
201
    if(GST_PAD_IS_LINKED(audiopad)) {
 
202
        g_object_unref(audiopad);
 
203
        return;
 
204
    }
 
205
 
 
206
    caps = gst_pad_get_caps(pad);
 
207
    str = gst_caps_get_structure(caps, 0);
 
208
    
 
209
    if(!g_strrstr(gst_structure_get_name(str), "audio")) {
 
210
        gst_caps_unref(caps);
 
211
        gst_object_unref(audiopad);
 
212
        return;
 
213
    }
 
214
   
 
215
    gst_caps_unref(caps);
 
216
    gst_pad_link(pad, audiopad);
 
217
}
 
218
 
 
219
static gboolean
 
220
gst_transcoder_create_pipeline(GstTranscoder *transcoder, 
 
221
    const char *input_uri, const char *output_uri, 
 
222
    const gchar *encoder_pipeline)
 
223
{
 
224
    GstElement *source_elem;
 
225
    GstElement *decoder_elem;
 
226
    GstElement *encoder_elem;
 
227
    GstElement *sink_elem;
 
228
    GstElement *conv_elem;
 
229
    GstElement *resample_elem;
 
230
    GstPad *encoder_pad;
 
231
 
 
232
    if(transcoder == NULL) {
 
233
        return FALSE;
 
234
    }
 
235
    
 
236
    transcoder->pipeline = gst_pipeline_new("pipeline");
 
237
 
 
238
    source_elem = gst_element_make_from_uri(GST_URI_SRC, input_uri, "source");
 
239
    if(source_elem == NULL) {
 
240
        gst_transcoder_raise_error(transcoder, _("Could not create source element"), NULL);
 
241
        return FALSE;
 
242
    }
 
243
 
 
244
    decoder_elem = gst_element_factory_make("decodebin2", "decodebin2");
 
245
    if(decoder_elem == NULL) {
 
246
        gst_transcoder_raise_error(transcoder, _("Could not create decodebin2 plugin"), NULL);
 
247
        return FALSE;
 
248
    }
 
249
    
 
250
    sink_elem = gst_element_make_from_uri(GST_URI_SINK, output_uri, "sink");
 
251
    if(sink_elem == NULL) {
 
252
        gst_transcoder_raise_error(transcoder, _("Could not create sink element"), NULL);
 
253
        return FALSE;
 
254
    }
 
255
    
 
256
    transcoder->sink_bin = gst_bin_new("sinkbin");
 
257
    if(transcoder->sink_bin == NULL) {
 
258
        gst_transcoder_raise_error(transcoder, _("Could not create sinkbin plugin"), NULL);
 
259
        return FALSE;
 
260
    }
 
261
    
 
262
    conv_elem = gst_element_factory_make("audioconvert", "audioconvert");
 
263
    if(conv_elem == NULL) {
 
264
        gst_transcoder_raise_error(transcoder, _("Could not create audioconvert plugin"), NULL);
 
265
        return FALSE;
 
266
    }
 
267
    
 
268
    resample_elem = gst_element_factory_make("audioresample", "audioresample");
 
269
    if(resample_elem == NULL) {
 
270
        gst_transcoder_raise_error(transcoder, _("Could not create audioresample plugin"), NULL);
 
271
        return FALSE;
 
272
    }
 
273
 
 
274
    encoder_elem = gst_transcoder_build_encoder(encoder_pipeline);
 
275
    if(encoder_elem == NULL) {
 
276
         gst_transcoder_raise_error(transcoder, _("Could not create encoding pipeline"), encoder_pipeline);
 
277
         return FALSE;
 
278
    }
 
279
 
 
280
    encoder_pad = gst_element_get_pad(conv_elem, "sink");
 
281
    if(encoder_pad == NULL) {
 
282
        gst_transcoder_raise_error(transcoder, _("Could not get sink pad from encoder"), NULL);
 
283
        return FALSE;
 
284
    }
 
285
    
 
286
    gst_bin_add_many(GST_BIN(transcoder->sink_bin), conv_elem, resample_elem, encoder_elem, sink_elem, NULL);
 
287
    gst_element_link_many(conv_elem, resample_elem, encoder_elem, sink_elem, NULL);
 
288
    
 
289
    gst_element_add_pad(transcoder->sink_bin, gst_ghost_pad_new("sink", encoder_pad));
 
290
    gst_object_unref(encoder_pad);
 
291
    
 
292
    gst_bin_add_many(GST_BIN(transcoder->pipeline), source_elem, decoder_elem, 
 
293
        transcoder->sink_bin, NULL);
 
294
        
 
295
    gst_element_link(source_elem, decoder_elem);
 
296
 
 
297
    g_signal_connect(decoder_elem, "new-decoded-pad", 
 
298
        G_CALLBACK(gst_transcoder_new_decoded_pad), transcoder);
 
299
 
 
300
    gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(transcoder->pipeline)), 
 
301
        gst_transcoder_bus_callback, transcoder);
 
302
    
 
303
    return TRUE;
 
304
}
 
305
 
 
306
// public methods
 
307
 
 
308
GstTranscoder *
 
309
gst_transcoder_new ()
 
310
{
 
311
    return g_new0 (GstTranscoder, 1);
 
312
}
 
313
 
 
314
void
 
315
gst_transcoder_free(GstTranscoder *transcoder)
 
316
{
 
317
    g_return_if_fail(transcoder != NULL);
 
318
    gst_transcoder_stop_iterate_timeout(transcoder);
 
319
    
 
320
    if(GST_IS_ELEMENT(transcoder->pipeline)) {
 
321
        gst_element_set_state(GST_ELEMENT(transcoder->pipeline), GST_STATE_NULL);
 
322
        gst_object_unref(GST_OBJECT(transcoder->pipeline));
 
323
    }
 
324
 
 
325
    if(transcoder->output_uri != NULL) {
 
326
        g_free(transcoder->output_uri);
 
327
        transcoder->output_uri = NULL;
 
328
    }
 
329
    
 
330
    g_free(transcoder);
 
331
    transcoder = NULL;
 
332
}
 
333
 
 
334
void 
 
335
gst_transcoder_transcode(GstTranscoder *transcoder, const gchar *input_uri, 
 
336
    const gchar *output_uri, const gchar *encoder_pipeline)
 
337
{
 
338
    g_return_if_fail(transcoder != NULL);
 
339
    
 
340
    if(transcoder->is_transcoding) {
 
341
        return;
 
342
    }
 
343
    
 
344
    if(!gst_transcoder_create_pipeline(transcoder, input_uri, output_uri, encoder_pipeline)) {
 
345
        gst_transcoder_raise_error(transcoder, _("Could not construct pipeline"), NULL); 
 
346
        return;
 
347
    }
 
348
    
 
349
    if(transcoder->output_uri != NULL) {
 
350
        g_free(transcoder->output_uri);
 
351
    }
 
352
    
 
353
    transcoder->output_uri = g_strdup(output_uri);
 
354
    transcoder->is_transcoding = TRUE;
 
355
    
 
356
    gst_element_set_state(GST_ELEMENT(transcoder->pipeline), GST_STATE_PLAYING);
 
357
    gst_transcoder_start_iterate_timeout(transcoder);
 
358
}
 
359
 
 
360
void 
 
361
gst_transcoder_cancel(GstTranscoder *transcoder)
 
362
{
 
363
    g_return_if_fail(transcoder != NULL);
 
364
    gst_transcoder_stop_iterate_timeout(transcoder);
 
365
    
 
366
    transcoder->is_transcoding = FALSE;
 
367
    
 
368
    if(GST_IS_ELEMENT(transcoder->pipeline)) {
 
369
        gst_element_set_state(GST_ELEMENT(transcoder->pipeline), GST_STATE_NULL);
 
370
        gst_object_unref(GST_OBJECT(transcoder->pipeline));
 
371
    }
 
372
    
 
373
    g_remove(transcoder->output_uri);
 
374
}
 
375
 
 
376
void
 
377
gst_transcoder_set_progress_callback(GstTranscoder *transcoder, 
 
378
    GstTranscoderProgressCallback cb)
 
379
{
 
380
    g_return_if_fail(transcoder != NULL);
 
381
    transcoder->progress_cb = cb;
 
382
}
 
383
 
 
384
void
 
385
gst_transcoder_set_finished_callback(GstTranscoder *transcoder, 
 
386
    GstTranscoderFinishedCallback cb)
 
387
{
 
388
    g_return_if_fail(transcoder != NULL);
 
389
    transcoder->finished_cb = cb;
 
390
}
 
391
 
 
392
void
 
393
gst_transcoder_set_error_callback(GstTranscoder *transcoder, 
 
394
    GstTranscoderErrorCallback cb)
 
395
{
 
396
    g_return_if_fail(transcoder != NULL);
 
397
    transcoder->error_cb = cb;
 
398
}
 
399
 
 
400
gboolean
 
401
gst_transcoder_get_is_transcoding(GstTranscoder *transcoder)
 
402
{
 
403
    g_return_val_if_fail(transcoder != NULL, FALSE);
 
404
    return transcoder->is_transcoding;
 
405
}