1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4
* Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
6
* Libbrasero-misc 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 2 of the License, or
9
* (at your option) any later version.
11
* The Libbrasero-misc authors hereby grant permission for non-GPL compatible
12
* GStreamer plugins to be used and distributed together with GStreamer
13
* and Libbrasero-misc. This permission is above and beyond the permissions granted
14
* by the GPL license by which Libbrasero-burn is covered. If you modify this code
15
* you may extend this exception to your version of the code, but you are not
16
* obligated to do so. If you do not wish to do so, delete this exception
17
* statement from your version.
19
* Libbrasero-misc is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU Library General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to:
26
* The Free Software Foundation, Inc.,
27
* 51 Franklin Street, Fifth Floor
28
* Boston, MA 02110-1301, USA.
38
#include <glib/gi18n-lib.h>
39
#include <glib-object.h>
41
#include <gdk-pixbuf/gdk-pixbuf.h>
44
#include <gst/base/gstbasesink.h>
45
#include <gst/pbutils/install-plugins.h>
46
#include <gst/pbutils/missing-plugins.h>
47
#include <gst/tag/tag.h>
49
#include "brasero-misc.h"
50
#include "brasero-metadata.h"
52
#define BRASERO_METADATA_SILENCE_INTERVAL 100000000LL
53
#define BRASERO_METADATA_INITIAL_STATE GST_STATE_PAUSED
55
struct BraseroMetadataPrivate {
63
GstElement *pipeline_mp3;
74
BraseroMetadataSilence *silence;
76
BraseroMetadataFlag flags;
77
BraseroMetadataInfo *info;
79
/* This is for automatic missing plugin install */
80
GSList *missing_plugins;
88
BraseroMetadataGetXidCb xid_callback;
89
gpointer xid_user_data;
92
guint moved_forward:1;
93
guint prev_level_mes:1;
96
guint snapshot_started:1;
98
typedef struct BraseroMetadataPrivate BraseroMetadataPrivate;
99
#define BRASERO_METADATA_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), BRASERO_TYPE_METADATA, BraseroMetadataPrivate))
109
} BraseroMetadataSignalType;
111
static guint brasero_metadata_signals [LAST_SIGNAL] = { 0 };
113
#define BRASERO_METADATA_IS_FAST(flags) \
114
(!((flags) & BRASERO_METADATA_FLAG_SILENCES) && \
115
((flags) & BRASERO_METADATA_FLAG_FAST))
117
G_DEFINE_TYPE (BraseroMetadata, brasero_metadata, G_TYPE_OBJECT)
119
static GSList *downloading = NULL;
120
static GSList *downloaded = NULL;
123
brasero_metadata_completed (BraseroMetadata *self);
126
brasero_metadata_get_xid (BraseroMetadata *metadata)
128
BraseroMetadataPrivate *priv;
130
priv = BRASERO_METADATA_PRIVATE (metadata);
131
if (!priv->xid_callback)
134
return priv->xid_callback (priv->xid_user_data);
138
brasero_metadata_set_get_xid_callback (BraseroMetadata *metadata,
139
BraseroMetadataGetXidCb callback,
142
BraseroMetadataPrivate *priv;
144
priv = BRASERO_METADATA_PRIVATE (metadata);
145
priv->xid_callback = callback;
146
priv->xid_user_data = user_data;
149
struct _BraseroMetadataGstDownload {
152
/* These are all metadata objects waiting */
155
typedef struct _BraseroMetadataGstDownload BraseroMetadataGstDownload;
158
brasero_metadata_info_clear (BraseroMetadataInfo *info)
163
if (info->snapshot) {
164
g_object_unref (info->snapshot);
165
info->snapshot = NULL;
175
g_free (info->title);
178
g_free (info->artist);
181
g_free (info->album);
184
g_free (info->genre);
186
if (info->musicbrainz_id)
187
g_free (info->musicbrainz_id);
189
if (info->silences) {
190
g_slist_foreach (info->silences, (GFunc) g_free, NULL);
191
g_slist_free (info->silences);
192
info->silences = NULL;
197
brasero_metadata_info_free (BraseroMetadataInfo *info)
202
brasero_metadata_info_clear (info);
208
brasero_metadata_info_copy (BraseroMetadataInfo *dest,
209
BraseroMetadataInfo *src)
216
dest->has_dts = src->has_dts;
217
dest->rate = src->rate;
218
dest->channels = src->channels;
219
dest->isrc = src->isrc;
220
dest->len = src->len;
221
dest->is_seekable = src->is_seekable;
222
dest->has_audio = src->has_audio;
223
dest->has_video = src->has_video;
226
dest->uri = g_strdup (src->uri);
229
dest->type = g_strdup (src->type);
232
dest->title = g_strdup (src->title);
235
dest->artist = g_strdup (src->artist);
238
dest->album = g_strdup (src->album);
241
dest->genre = g_strdup (src->genre);
243
if (src->musicbrainz_id)
244
dest->musicbrainz_id = g_strdup (src->musicbrainz_id);
247
dest->snapshot = src->snapshot;
248
g_object_ref (dest->snapshot);
251
for (iter = src->silences; iter; iter = iter->next) {
252
BraseroMetadataSilence *silence, *copy;
254
silence = iter->data;
256
copy = g_new0 (BraseroMetadataSilence, 1);
257
copy->start = silence->start;
258
copy->end = silence->end;
260
dest->silences = g_slist_append (dest->silences, copy);
265
brasero_metadata_stop_pipeline (GstElement *pipeline)
268
GstStateChangeReturn change;
270
change = gst_element_set_state (GST_ELEMENT (pipeline),
273
change = gst_element_get_state (pipeline,
278
/* better wait for the state change to be completed */
279
while (change == GST_STATE_CHANGE_ASYNC && state != GST_STATE_NULL) {
282
change = gst_element_get_state (pipeline,
286
BRASERO_UTILS_LOG ("Get state (current = %i pending = %i) returned %i",
287
state, pending, change);
290
if (change == GST_STATE_CHANGE_FAILURE)
291
g_warning ("State change failure");
296
brasero_metadata_destroy_pipeline (BraseroMetadata *self)
298
BraseroMetadataPrivate *priv;
300
priv = BRASERO_METADATA_PRIVATE (self);
304
if (priv->pipeline_mp3) {
305
brasero_metadata_stop_pipeline (priv->pipeline_mp3);
306
gst_object_unref (GST_OBJECT (priv->pipeline_mp3));
307
priv->pipeline_mp3 = NULL;
310
if (priv->watch_mp3) {
311
g_source_remove (priv->watch_mp3);
318
brasero_metadata_stop_pipeline (priv->pipeline);
321
gst_bin_remove (GST_BIN (priv->pipeline), priv->audio);
326
gst_bin_remove (GST_BIN (priv->pipeline), priv->video);
327
priv->snapshot = NULL;
331
gst_object_unref (GST_OBJECT (priv->pipeline));
332
priv->pipeline = NULL;
335
gst_object_unref (GST_OBJECT (priv->level));
340
gst_object_unref (GST_OBJECT (priv->sink));
345
gst_object_unref (GST_OBJECT (priv->convert));
346
priv->convert = NULL;
351
brasero_metadata_stop (BraseroMetadata *self)
353
BraseroMetadataPrivate *priv;
356
priv = BRASERO_METADATA_PRIVATE (self);
358
BRASERO_UTILS_LOG ("Retrieval ended for %s %p",
359
priv->info ? priv->info->uri:"Unknown",
362
g_mutex_lock (priv->mutex);
364
/* Destroy the pipeline as it has become un-re-usable */
366
g_source_remove (priv->watch);
371
brasero_metadata_destroy_pipeline (self);
373
/* That's automatic missing plugin installation */
374
if (priv->missing_plugins) {
375
g_slist_foreach (priv->missing_plugins,
376
(GFunc) gst_mini_object_unref,
378
g_slist_free (priv->missing_plugins);
379
priv->missing_plugins = NULL;
382
if (priv->downloads) {
385
for (iter = priv->downloads; iter; iter = iter->next) {
386
BraseroMetadataGstDownload *download;
388
download = iter->data;
389
download->objects = g_slist_remove (download->objects, self);
392
g_slist_free (priv->downloads);
393
priv->downloads = NULL;
396
/* stop the pipeline */
399
/* Tell all the waiting threads that we're done */
400
for (iter = priv->conditions; iter; iter = iter->next) {
403
condition = iter->data;
404
g_cond_broadcast (condition);
407
g_mutex_unlock (priv->mutex);
411
brasero_metadata_cancel (BraseroMetadata *self)
413
BraseroMetadataPrivate *priv;
415
priv = BRASERO_METADATA_PRIVATE (self);
417
BRASERO_UTILS_LOG ("Metadata retrieval cancelled for %s %p",
418
priv->info ? priv->info->uri:"Unknown",
421
brasero_metadata_stop (self);
423
g_error_free (priv->error);
428
brasero_metadata_install_plugins_add_downloaded (GSList *downloads)
432
for (iter = downloads; iter; iter = iter->next) {
433
BraseroMetadataGstDownload *download;
435
download = iter->data;
436
downloaded = g_slist_prepend (downloaded, download->detail);
437
download->detail = NULL;
442
brasero_metadata_install_plugins_free_data (GSList *downloads)
446
for (iter = downloads; iter; iter = iter->next) {
447
BraseroMetadataGstDownload *download;
450
download = iter->data;
451
if (download->detail)
452
g_free (download->detail);
454
for (meta = download->objects; meta; meta = meta->next) {
455
BraseroMetadataPrivate *priv;
457
priv = BRASERO_METADATA_PRIVATE (meta->data);
458
priv->downloads = g_slist_remove (priv->downloads, download);
460
g_slist_free (download->objects);
462
downloading = g_slist_remove (downloading, download);
466
g_slist_free (downloads);
470
brasero_metadata_install_plugins_success (BraseroMetadataGstDownload *download)
474
for (iter = download->objects; iter; iter = iter->next) {
475
BraseroMetadataPrivate *priv;
477
priv = BRASERO_METADATA_PRIVATE (iter->data);
480
/* free previously saved error message */
481
g_error_free (priv->error);
485
gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_NULL);
486
gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PLAYING);
491
brasero_metadata_install_plugins_abort (BraseroMetadataGstDownload *download)
496
for (iter = download->objects; iter; iter = next) {
497
BraseroMetadataPrivate *priv;
501
priv = BRASERO_METADATA_PRIVATE (iter->data);
504
g_error_free (priv->error);
508
brasero_metadata_completed (BRASERO_METADATA (iter->data));
513
brasero_metadata_install_plugins_completed (BraseroMetadataGstDownload *download)
518
for (iter = download->objects; iter; iter = next) {
520
brasero_metadata_completed (BRASERO_METADATA (iter->data));
525
brasero_metadata_install_plugins_result (GstInstallPluginsReturn res,
528
GSList *downloads = data;
532
case GST_INSTALL_PLUGINS_PARTIAL_SUCCESS:
533
case GST_INSTALL_PLUGINS_SUCCESS:
534
brasero_metadata_install_plugins_add_downloaded (downloads);
536
/* force gst to update plugin list */
537
gst_update_registry ();
539
/* restart metadata search */
540
for (iter = downloads; iter; iter = iter->next) {
541
BraseroMetadataGstDownload *download;
543
download = iter->data;
544
brasero_metadata_install_plugins_success (download);
548
case GST_INSTALL_PLUGINS_NOT_FOUND:
549
brasero_metadata_install_plugins_add_downloaded (downloads);
551
/* stop everything */
552
for (iter = downloads; iter; iter = iter->next)
553
brasero_metadata_install_plugins_completed (iter->data);
556
case GST_INSTALL_PLUGINS_USER_ABORT:
557
brasero_metadata_install_plugins_add_downloaded (downloads);
559
/* free previously saved error message */
560
for (iter = downloads; iter; iter = iter->next) {
561
BraseroMetadataGstDownload *download;
563
download = iter->data;
564
brasero_metadata_install_plugins_abort (download);
568
case GST_INSTALL_PLUGINS_ERROR:
569
case GST_INSTALL_PLUGINS_CRASHED:
571
for (iter = downloads; iter; iter = iter->next)
572
brasero_metadata_install_plugins_completed (iter->data);
577
brasero_metadata_install_plugins_free_data (downloads);
580
static BraseroMetadataGstDownload *
581
brasero_metadata_is_downloading (const gchar *detail)
585
for (iter = downloading; iter; iter = iter->next) {
586
BraseroMetadataGstDownload *download;
588
download = iter->data;
589
if (!strcmp (download->detail, detail))
597
brasero_metadata_install_missing_plugins (BraseroMetadata *self)
599
GstInstallPluginsContext *context;
600
GstInstallPluginsReturn status;
601
BraseroMetadataPrivate *priv;
602
GSList *downloads = NULL;
606
priv = BRASERO_METADATA_PRIVATE (self);
608
BRASERO_UTILS_LOG ("Starting to download missing plugins");
610
details = g_ptr_array_new ();
611
for (iter = priv->missing_plugins; iter; iter = iter->next) {
613
BraseroMetadataGstDownload *download;
615
/* Check if this plugin:
616
* - has already been downloaded (whether it was successful or not)
617
* - is being downloaded
618
* If so don't do anything. */
619
detail = gst_missing_plugin_message_get_installer_detail (iter->data);
620
gst_mini_object_unref (iter->data);
622
download = brasero_metadata_is_downloading (detail);
624
download->objects = g_slist_prepend (download->objects, self);
629
if (g_slist_find_custom (downloaded, detail, (GCompareFunc) strcmp)) {
634
download = g_new0 (BraseroMetadataGstDownload, 1);
635
download->detail = detail;
636
download->objects = g_slist_prepend (download->objects, self);
637
priv->downloads = g_slist_prepend (priv->downloads, download);
639
downloads = g_slist_prepend (downloads, download);
640
downloading = g_slist_prepend (downloading, download);
642
g_ptr_array_add (details, detail);
645
g_slist_free (priv->missing_plugins);
646
priv->missing_plugins = NULL;
649
/* either these plugins were downloaded or are being downloaded */
650
g_ptr_array_free (details, TRUE);
651
if (!priv->downloads)
657
g_ptr_array_add (details, NULL);
659
/* FIXME: we'd need the main window here to set it modal */
661
context = gst_install_plugins_context_new ();
662
gst_install_plugins_context_set_xid (context, brasero_metadata_get_xid (self));
663
status = gst_install_plugins_async ((gchar **) details->pdata,
665
brasero_metadata_install_plugins_result,
668
gst_install_plugins_context_free (context);
669
g_ptr_array_free (details, TRUE);
671
BRASERO_UTILS_LOG ("Download status %i", status);
673
if (status != GST_INSTALL_PLUGINS_STARTED_OK) {
674
brasero_metadata_install_plugins_free_data (downloads);
682
brasero_metadata_completed (BraseroMetadata *self)
684
BraseroMetadataPrivate *priv;
686
priv = BRASERO_METADATA_PRIVATE (self);
689
BRASERO_UTILS_LOG ("Operation completed with an error %s", priv->error->message);
692
/* See if we have missing plugins */
693
if (priv->missing_plugins) {
694
if (brasero_metadata_install_missing_plugins (self))
698
/* we send a message only if we haven't got a loop (= async mode) */
700
g_signal_emit (G_OBJECT (self),
701
brasero_metadata_signals [COMPLETED_SIGNAL],
705
brasero_metadata_stop (self);
707
g_object_unref (self);
709
/* Return FALSE on purpose here as it will stop the bus callback
710
* It's not whether we succeeded or not. */
715
brasero_metadata_thumbnail (BraseroMetadata *self)
717
BraseroMetadataPrivate *priv;
721
priv = BRASERO_METADATA_PRIVATE (self);
723
/* find the right position and move forward */
724
position = 15 * GST_SECOND;
725
while (position > 0 && position >= priv->info->len)
726
position -= 5 * GST_SECOND;
731
gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
733
priv->snapshot_started = 1;
734
if (position < GST_SECOND)
735
position = GST_SECOND;
737
res = gst_element_seek_simple (priv->pipeline,
742
BRASERO_UTILS_LOG ("Seeking forward %i for %s", res, priv->info->uri);
744
return brasero_metadata_completed (self);
746
g_object_set (priv->snapshot,
747
"send-messages", TRUE,
754
brasero_metadata_is_seekable (BraseroMetadata *self)
759
BraseroMetadataPrivate *priv;
761
priv = BRASERO_METADATA_PRIVATE (self);
763
priv->info->is_seekable = FALSE;
765
/* NOTE: apparently GST_FORMAT_DEFAULT does not work here */
766
query = gst_query_new_seeking (GST_FORMAT_TIME);
768
/* NOTE: it works better now on the pipeline than on the source as we
770
if (!gst_element_query (priv->pipeline, query))
773
gst_query_parse_seeking (query,
779
priv->info->is_seekable = seekable;
783
gst_query_unref (query);
786
/* FIXME: use GstDiscoverer ? */
788
brasero_metadata_get_mime_type (BraseroMetadata *self)
790
BraseroMetadataPrivate *priv;
791
GstElement *typefind;
792
GstCaps *caps = NULL;
795
priv = BRASERO_METADATA_PRIVATE (self);
797
if (priv->info->type) {
798
g_free (priv->info->type);
799
priv->info->type = NULL;
802
/* find the type of the file */
803
typefind = gst_bin_get_by_name (GST_BIN (priv->decode),
806
g_object_get (typefind, "caps", &caps, NULL);
808
gst_object_unref (typefind);
812
if (gst_caps_get_size (caps) <= 0) {
813
gst_object_unref (typefind);
817
mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
818
gst_object_unref (typefind);
820
BRASERO_UTILS_LOG ("Mime type %s", mime);
825
if (!strcmp (mime, "application/x-id3"))
826
priv->info->type = g_strdup ("audio/mpeg");
827
else if (!strcmp (mime, "audio/x-wav")) {
828
GstElement *wavparse = NULL;
829
GstIteratorResult res;
831
GValue value = { 0, };
833
priv->info->type = g_strdup (mime);
835
/* make sure it doesn't have dts inside */
836
iter = gst_bin_iterate_recurse (GST_BIN (priv->decode));
838
res = gst_iterator_next (iter, &value);
839
while (res == GST_ITERATOR_OK) {
843
element = GST_ELEMENT (g_value_get_object (&value));
844
name = gst_object_get_name (GST_OBJECT (element));
846
if (!strncmp (name, "wavparse", 8)) {
847
wavparse = gst_object_ref (element);
848
g_value_unset (&value);
855
g_value_unset (&value);
858
res = gst_iterator_next (iter, &value);
860
gst_iterator_free (iter);
866
src_pad = gst_element_get_static_pad (wavparse, "src");
867
src_caps = gst_pad_get_current_caps (src_pad);
868
gst_object_unref (src_pad);
872
GstStructure *structure;
874
/* negotiated caps will always have one structure */
875
structure = gst_caps_get_structure (src_caps, 0);
876
priv->info->has_dts = gst_structure_has_name (structure, "audio/x-dts");
877
gst_caps_unref (src_caps);
879
gst_object_unref (wavparse);
882
BRASERO_UTILS_LOG ("Wav file has dts: %s", priv->info->has_dts? "yes":"no");
885
priv->info->type = g_strdup (mime);
891
brasero_metadata_is_mp3 (BraseroMetadata *self)
893
BraseroMetadataPrivate *priv;
895
priv = BRASERO_METADATA_PRIVATE (self);
897
if (!priv->info->type
898
&& !brasero_metadata_get_mime_type (self))
901
if (!strcmp (priv->info->type, "audio/mpeg"))
908
foreach_tag (const GstTagList *list,
910
BraseroMetadata *self)
912
BraseroMetadataPrivate *priv;
913
priv = BRASERO_METADATA_PRIVATE (self);
915
if (!strcmp (tag, GST_TAG_TITLE)) {
916
if (priv->info->title)
917
g_free (priv->info->title);
919
gst_tag_list_get_string (list, tag, &(priv->info->title));
920
} else if (!strcmp (tag, GST_TAG_ARTIST)
921
|| !strcmp (tag, GST_TAG_PERFORMER)) {
922
if (priv->info->artist)
923
g_free (priv->info->artist);
925
gst_tag_list_get_string (list, tag, &(priv->info->artist));
927
else if (!strcmp (tag, GST_TAG_ALBUM)) {
928
if (priv->info->album)
929
g_free (priv->info->album);
931
gst_tag_list_get_string (list, tag, &(priv->info->album));
933
else if (!strcmp (tag, GST_TAG_GENRE)) {
934
if (priv->info->genre)
935
g_free (priv->info->genre);
937
gst_tag_list_get_string (list, tag, &(priv->info->genre));
939
/* else if (!strcmp (tag, GST_TAG_COMPOSER)) {
941
g_free (self->composer);
943
gst_tag_list_get_string (list, tag, &(self->composer));
945
*/ else if (!strcmp (tag, GST_TAG_ISRC)) {
947
gst_tag_list_get_string (list, tag, &isrc);
950
priv->info->isrc = (int) g_ascii_strtoull (isrc, NULL, 10);
952
else if (!strcmp (tag, GST_TAG_MUSICBRAINZ_TRACKID)) {
953
gst_tag_list_get_string (list, tag, &(priv->info->musicbrainz_id));
958
brasero_metadata_process_element_messages (BraseroMetadata *self,
961
BraseroMetadataPrivate *priv;
962
const GstStructure *s;
964
priv = BRASERO_METADATA_PRIVATE (self);
966
s = gst_message_get_structure (msg);
968
/* This is for snapshot function */
969
if (gst_message_has_name (msg, "preroll-pixbuf")
970
|| gst_message_has_name (msg, "pixbuf")) {
973
value = gst_structure_get_value (s, "pixbuf");
974
priv->info->snapshot = g_value_get_object (value);
975
g_object_ref (priv->info->snapshot);
977
BRASERO_UTILS_LOG ("Received pixbuf snapshot sink (%p) for %s", priv->info->snapshot, priv->info->uri);
979
/* Now we can stop */
980
return brasero_metadata_completed (self);
983
/* here we just want to check if that's a missing codec */
984
if ((priv->flags & BRASERO_METADATA_FLAG_MISSING)
985
&& gst_is_missing_plugin_message (msg)) {
986
priv->missing_plugins = g_slist_prepend (priv->missing_plugins, gst_message_ref (msg));
988
else if (gst_message_has_name (msg, "level")
989
&& gst_structure_has_field (s, "peak")) {
994
/* FIXME: this might still be changed to GValueArray before 1.0 release */
995
list = gst_structure_get_value (s, "peak");
996
value = gst_value_list_get_value (list, 0);
997
peak = g_value_get_double (value);
999
/* detection of silence */
1003
/* was there a silence last time we check ?
1004
* NOTE: if that's the first signal we receive
1005
* then consider that silence started from 0 */
1006
gst_element_query_position (priv->pipeline, GST_FORMAT_TIME, &pos);
1008
BRASERO_UTILS_LOG ("impossible to retrieve position");
1012
if (!priv->silence) {
1013
priv->silence = g_new0 (BraseroMetadataSilence, 1);
1014
if (priv->prev_level_mes) {
1015
priv->silence->start = pos;
1016
priv->silence->end = pos;
1019
priv->silence->start = 0;
1020
priv->silence->end = pos;
1024
priv->silence->end = pos;
1026
BRASERO_UTILS_LOG ("silence detected at %lli", pos);
1028
else if (priv->silence) {
1029
BRASERO_UTILS_LOG ("silence finished");
1031
priv->info->silences = g_slist_append (priv->info->silences,
1033
priv->silence = NULL;
1035
priv->prev_level_mes = 1;
1042
brasero_metadata_process_pending_messages (BraseroMetadata *self)
1046
BraseroMetadataPrivate *priv;
1048
priv = BRASERO_METADATA_PRIVATE (self);
1050
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
1051
while ((msg = gst_bus_pop (bus))) {
1052
GstTagList *tags = NULL;
1054
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_TAG) {
1055
gst_message_parse_tag (msg, &tags);
1056
gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, self);
1057
gst_tag_list_free (tags);
1059
else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT)
1060
brasero_metadata_process_element_messages (self, msg);
1062
gst_message_unref (msg);
1065
g_object_unref (bus);
1069
brasero_metadata_success (BraseroMetadata *self)
1071
BraseroMetadataPrivate *priv;
1073
priv = BRASERO_METADATA_PRIVATE (self);
1075
BRASERO_UTILS_LOG ("Metadata retrieval completed for %s", priv->info->uri);
1077
/* check if that's a seekable one */
1078
brasero_metadata_is_seekable (self);
1080
if (priv->silence) {
1081
priv->silence->end = priv->info->len;
1082
priv->info->silences = g_slist_append (priv->info->silences, priv->silence);
1083
priv->silence = NULL;
1086
/* before leaving, check if we need a snapshot */
1087
if (priv->info->len > 0
1089
&& priv->video_linked
1090
&& !priv->snapshot_started)
1091
return brasero_metadata_thumbnail (self);
1093
return brasero_metadata_completed (self);
1097
brasero_metadata_get_duration (BraseroMetadata *self,
1098
GstElement *pipeline,
1099
gboolean use_duration)
1101
BraseroMetadataPrivate *priv;
1102
gint64 duration = -1;
1104
priv = BRASERO_METADATA_PRIVATE (self);
1107
gst_element_query_position (GST_ELEMENT (pipeline),
1111
gst_element_query_duration (GST_ELEMENT (pipeline),
1115
if (duration == -1) {
1119
BRASERO_GET_BASENAME_FOR_DISPLAY (priv->info->uri, name);
1120
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1121
BRASERO_UTILS_ERROR_GENERAL,
1122
_("\"%s\" could not be handled by GStreamer."),
1127
return brasero_metadata_completed (self);
1130
BRASERO_UTILS_LOG ("Found duration %lli for %s", duration, priv->info->uri);
1132
priv->info->len = duration;
1133
return brasero_metadata_success (self);
1137
* This is to deal with mp3 more particularly the vbrs
1141
brasero_metadata_mp3_bus_messages (GstBus *bus,
1143
BraseroMetadata *self)
1145
BraseroMetadataPrivate *priv;
1146
gchar *debug_string = NULL;
1147
GError *error = NULL;
1149
priv = BRASERO_METADATA_PRIVATE (self);
1151
switch (GST_MESSAGE_TYPE (msg)) {
1152
case GST_MESSAGE_ERROR:
1153
/* save the error message */
1154
gst_message_parse_error (msg, &error, &debug_string);
1155
BRASERO_UTILS_LOG ("GStreamer error - mp3 - (%s)", debug_string);
1156
g_free (debug_string);
1157
if (!priv->error && error)
1158
priv->error = error;
1160
brasero_metadata_completed (self);
1163
case GST_MESSAGE_EOS:
1164
BRASERO_UTILS_LOG ("End of stream reached - mp3 - for %s", priv->info->uri);
1165
brasero_metadata_get_duration (self, priv->pipeline_mp3, FALSE);
1176
brasero_metadata_create_mp3_pipeline (BraseroMetadata *self)
1178
BraseroMetadataPrivate *priv;
1184
priv = BRASERO_METADATA_PRIVATE (self);
1186
priv->pipeline_mp3 = gst_pipeline_new (NULL);
1188
source = gst_element_make_from_uri (GST_URI_SRC,
1192
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1193
BRASERO_UTILS_ERROR_GENERAL,
1194
_("%s element could not be created"),
1197
g_object_unref (priv->pipeline_mp3);
1198
priv->pipeline_mp3 = NULL;
1201
gst_bin_add (GST_BIN (priv->pipeline_mp3), source);
1203
parse = gst_element_factory_make ("mp3parse", NULL);
1205
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1206
BRASERO_UTILS_ERROR_GENERAL,
1207
_("%s element could not be created"),
1210
g_object_unref (priv->pipeline_mp3);
1211
priv->pipeline_mp3 = NULL;
1214
gst_bin_add (GST_BIN (priv->pipeline_mp3), parse);
1216
sink = gst_element_factory_make ("fakesink", NULL);
1218
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1219
BRASERO_UTILS_ERROR_GENERAL,
1220
_("%s element could not be created"),
1223
g_object_unref (priv->pipeline_mp3);
1224
priv->pipeline_mp3 = NULL;
1227
gst_bin_add (GST_BIN (priv->pipeline_mp3), sink);
1230
if (!gst_element_link_many (source, parse, sink, NULL)) {
1231
g_object_unref (priv->pipeline_mp3);
1232
priv->pipeline_mp3 = NULL;
1237
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline_mp3));
1238
priv->watch_mp3 = gst_bus_add_watch (bus,
1239
(GstBusFunc) brasero_metadata_mp3_bus_messages,
1241
gst_object_unref (bus);
1243
gst_element_set_state (priv->pipeline_mp3, GST_STATE_PLAYING);
1248
brasero_metadata_success_main (BraseroMetadata *self)
1250
BraseroMetadataPrivate *priv;
1252
priv = BRASERO_METADATA_PRIVATE (self);
1254
BRASERO_UTILS_LOG ("Metadata retrieval successfully completed for %s", priv->info->uri);
1256
/* find the type of the file */
1257
brasero_metadata_get_mime_type (self);
1259
/* empty the bus of any pending message */
1260
brasero_metadata_process_pending_messages (self);
1263
if (brasero_metadata_is_mp3 (self)) {
1264
if (!brasero_metadata_create_mp3_pipeline (self)) {
1265
BRASERO_UTILS_LOG ("Impossible to run mp3 specific pipeline");
1266
return brasero_metadata_completed (self);
1269
/* Return FALSE here not because we failed but to stop the Bus callback */
1273
return brasero_metadata_get_duration (self, priv->pipeline, TRUE);
1277
brasero_metadata_bus_messages (GstBus *bus,
1279
BraseroMetadata *self)
1281
BraseroMetadataPrivate *priv;
1282
GstStateChangeReturn result;
1283
gchar *debug_string = NULL;
1284
GstTagList *tags = NULL;
1285
GError *error = NULL;
1288
priv = BRASERO_METADATA_PRIVATE (self);
1290
switch (GST_MESSAGE_TYPE (msg)) {
1291
case GST_MESSAGE_ELEMENT:
1292
return brasero_metadata_process_element_messages (self, msg);
1294
case GST_MESSAGE_ERROR:
1295
/* save the error message */
1296
gst_message_parse_error (msg, &error, &debug_string);
1297
BRASERO_UTILS_LOG ("GStreamer error (%s)", debug_string);
1298
g_free (debug_string);
1299
if (!priv->error && error)
1300
priv->error = error;
1302
return brasero_metadata_completed (self);
1304
case GST_MESSAGE_EOS:
1305
BRASERO_UTILS_LOG ("End of stream reached for %s", priv->info->uri);
1306
return brasero_metadata_success_main (self);
1308
case GST_MESSAGE_TAG:
1309
gst_message_parse_tag (msg, &tags);
1310
gst_tag_list_foreach (tags, (GstTagForeachFunc) foreach_tag, self);
1311
gst_tag_list_free (tags);
1314
case GST_MESSAGE_STATE_CHANGED:
1315
/* when stopping the pipeline we are only interested in TAGS */
1316
result = gst_element_get_state (GST_ELEMENT (priv->pipeline),
1321
if (result != GST_STATE_CHANGE_SUCCESS)
1324
if (newstate != GST_STATE_PAUSED && newstate != GST_STATE_PLAYING)
1327
if (!priv->snapshot_started)
1328
return brasero_metadata_success_main (self);
1340
brasero_metadata_create_audio_pipeline (BraseroMetadata *self)
1342
BraseroMetadataPrivate *priv;
1345
priv = BRASERO_METADATA_PRIVATE (self);
1347
priv->audio = gst_bin_new (NULL);
1349
/* set up the pipeline according to flags */
1350
if (priv->flags & BRASERO_METADATA_FLAG_SILENCES) {
1351
priv->prev_level_mes = 0;
1353
/* Add a reference to these objects as we want to keep them
1354
* around after the bin they've been added to is destroyed
1355
* NOTE: now we destroy the pipeline every time which means
1356
* that it doesn't really matter. */
1358
priv->level = gst_element_factory_make ("level", NULL);
1360
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1361
BRASERO_UTILS_ERROR_GENERAL,
1362
_("%s element could not be created"),
1364
gst_object_unref (priv->audio);
1368
g_object_set (priv->level,
1370
"interval", (guint64) BRASERO_METADATA_SILENCE_INTERVAL,
1374
gst_object_ref (priv->convert);
1375
gst_object_ref (priv->level);
1376
gst_object_ref (priv->sink);
1378
gst_bin_add_many (GST_BIN (priv->audio),
1384
if (!gst_element_link_many (priv->convert,
1388
BRASERO_UTILS_LOG ("Impossible to link elements");
1389
gst_object_unref (priv->audio);
1394
audio_pad = gst_element_get_static_pad (priv->convert, "sink");
1396
else if (priv->flags & BRASERO_METADATA_FLAG_THUMBNAIL) {
1399
queue = gst_element_factory_make ("queue", NULL);
1400
gst_object_ref (priv->convert);
1401
gst_object_ref (priv->sink);
1403
gst_bin_add_many (GST_BIN (priv->audio),
1408
if (!gst_element_link_many (queue,
1412
BRASERO_UTILS_LOG ("Impossible to link elements");
1413
gst_object_unref (priv->audio);
1418
audio_pad = gst_element_get_static_pad (queue, "sink");
1423
queue = gst_element_factory_make ("queue", NULL);
1424
gst_bin_add (GST_BIN (priv->audio), queue);
1426
gst_object_ref (priv->sink);
1427
gst_bin_add (GST_BIN (priv->audio), priv->sink);
1429
if (!gst_element_link (queue, priv->sink)) {
1430
BRASERO_UTILS_LOG ("Impossible to link elements");
1431
gst_object_unref (priv->audio);
1436
audio_pad = gst_element_get_static_pad (queue, "sink");
1439
gst_element_add_pad (priv->audio, gst_ghost_pad_new ("sink", audio_pad));
1440
gst_object_unref (audio_pad);
1442
gst_bin_add (GST_BIN (priv->pipeline), priv->audio);
1443
BRASERO_UTILS_LOG ("Adding audio pipeline for %s", priv->info->uri);
1449
brasero_metadata_create_video_pipeline (BraseroMetadata *self)
1451
BraseroMetadataPrivate *priv;
1452
GstElement *colorspace;
1456
priv = BRASERO_METADATA_PRIVATE (self);
1457
priv->video = gst_bin_new (NULL);
1459
priv->snapshot = gst_element_factory_make ("gdkpixbufsink", NULL);
1460
if (!priv->snapshot) {
1461
gst_object_unref (priv->video);
1464
BRASERO_UTILS_LOG ("gdkpixbufsink is not installed");
1467
gst_bin_add (GST_BIN (priv->video), priv->snapshot);
1469
g_object_set (priv->snapshot,
1471
"send-messages", FALSE,
1472
"max-lateness", (gint64) - 1,
1475
colorspace = gst_element_factory_make ("videoconvert", NULL);
1477
gst_object_unref (priv->video);
1480
BRASERO_UTILS_LOG ("videoconvert is not installed");
1483
gst_bin_add (GST_BIN (priv->video), colorspace);
1485
queue = gst_element_factory_make ("queue", NULL);
1486
gst_bin_add (GST_BIN (priv->video), queue);
1489
if (!gst_element_link_many (queue,
1493
gst_object_unref (priv->video);
1496
BRASERO_UTILS_LOG ("Impossible to link elements");
1500
video_pad = gst_element_get_static_pad (queue, "sink");
1501
gst_element_add_pad (priv->video, gst_ghost_pad_new ("sink", video_pad));
1502
gst_object_unref (video_pad);
1504
gst_bin_add (GST_BIN (priv->pipeline), priv->video);
1505
BRASERO_UTILS_LOG ("Adding pixbuf snapshot sink for %s", priv->info->uri);
1511
brasero_metadata_error_on_pad_linking (BraseroMetadata *self)
1513
BraseroMetadataPrivate *priv;
1514
GstMessage *message;
1517
priv = BRASERO_METADATA_PRIVATE (self);
1519
message = gst_message_new_error (GST_OBJECT (priv->pipeline),
1521
"Sent by brasero_metadata_error_on_pad_linking");
1523
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
1524
gst_bus_post (bus, message);
1525
g_object_unref (bus);
1529
brasero_metadata_link_dummy_pad (BraseroMetadata *self,
1532
BraseroMetadataPrivate *priv;
1533
GstElement *fakesink;
1534
GstPadLinkReturn res;
1537
priv = BRASERO_METADATA_PRIVATE (self);
1539
BRASERO_UTILS_LOG ("Linking to a fake sink");
1541
/* It doesn't hurt to link to a fakesink and can avoid some deadlocks.
1542
* I don't know why but some demuxers in particular will lock (probably
1543
* because they can't output video) if only their audio streams are
1544
* linked and not their video streams (one example is dv demuxer).
1545
* NOTE: there must also be a queue for audio streams. */
1546
fakesink = gst_element_factory_make ("fakesink", NULL);
1550
gst_bin_add (GST_BIN (priv->pipeline), fakesink);
1551
sink = gst_element_get_static_pad (fakesink, "sink");
1555
res = gst_pad_link (pad, sink);
1557
if (res == GST_PAD_LINK_OK) {
1558
gst_element_set_state (fakesink, BRASERO_METADATA_INITIAL_STATE);
1566
brasero_metadata_audio_caps (BraseroMetadata *self,
1571
BraseroMetadataPrivate *priv;
1573
priv = BRASERO_METADATA_PRIVATE (self);
1575
num_caps = gst_caps_get_size (caps);
1576
for (i = 0; i < num_caps; i++) {
1577
const GstStructure *structure;
1579
structure = gst_caps_get_structure (caps, i);
1583
if (gst_structure_has_field (structure, "channels")) {
1584
if (gst_structure_get_field_type (structure, "channels") == G_TYPE_INT) {
1585
priv->info->channels = 0;
1586
gst_structure_get_int (structure, "channels", &priv->info->channels);
1588
BRASERO_UTILS_LOG ("Number of channels %i", priv->info->channels);
1590
else if (gst_structure_get_field_type (structure, "channels") == GST_TYPE_INT_RANGE) {
1591
const GValue *value;
1593
value = gst_structure_get_value (structure, "channels");
1595
priv->info->channels = gst_value_get_int_range_max (value);
1596
BRASERO_UTILS_LOG ("Number of channels %i", priv->info->channels);
1599
else if (gst_structure_get_field_type (structure, "channels") != G_TYPE_INVALID) {
1600
BRASERO_UTILS_LOG ("Unhandled type for channel prop %s",
1601
g_type_name (gst_structure_get_field_type (structure, "channels")));
1605
if (gst_structure_has_field (structure, "rate")) {
1606
if (gst_structure_get_field_type (structure, "rate") == G_TYPE_INT) {
1607
priv->info->rate = 0;
1608
gst_structure_get_int (structure, "rate", &priv->info->rate);
1610
BRASERO_UTILS_LOG ("Rate %i", priv->info->rate);
1612
else if (gst_structure_get_field_type (structure, "rate") == GST_TYPE_INT_RANGE) {
1613
const GValue *value;
1615
value = gst_structure_get_value (structure, "rate");
1617
priv->info->rate = gst_value_get_int_range_max (value);
1618
BRASERO_UTILS_LOG ("Rate %i", priv->info->rate);
1621
else if (gst_structure_get_field_type (structure, "rate") != G_TYPE_INVALID) {
1622
BRASERO_UTILS_LOG ("Unhandled type for rate prop %s",
1623
g_type_name (gst_structure_get_field_type (structure, "rate")));
1630
brasero_metadata_new_decoded_pad_cb (GstElement *decode,
1632
BraseroMetadata *self)
1639
GstPadLinkReturn res;
1640
GstStructure *structure;
1641
BraseroMetadataPrivate *priv;
1643
priv = BRASERO_METADATA_PRIVATE (self);
1645
res = GST_PAD_LINK_REFUSED;
1647
BRASERO_UTILS_LOG ("New pad for %s", priv->info->uri);
1649
/* make sure that this is audio / video */
1650
/* FIXME: get_current_caps() doesn't always seem to work yet here */
1651
caps = gst_pad_query_caps (pad, NULL);
1653
g_warning ("Expected caps on decodebin pad %s", GST_PAD_NAME (pad));
1656
structure = gst_caps_get_structure (caps, 0);
1657
name = gst_structure_get_name (structure);
1659
has_audio = (g_strrstr (name, "audio") != NULL);
1660
has_video = (g_strrstr (name, "video") != NULL);
1661
priv->info->has_audio |= has_audio;
1662
priv->info->has_video |= has_video;
1664
if (has_audio && !priv->audio_linked) {
1665
brasero_metadata_audio_caps (self, caps);
1666
brasero_metadata_create_audio_pipeline (self);
1667
sink = gst_element_get_static_pad (priv->audio, "sink");
1668
if (sink && !GST_PAD_IS_LINKED (sink)) {
1669
res = gst_pad_link (pad, sink);
1670
BRASERO_UTILS_LOG ("Audio stream link %i for %s", res, priv->info->uri);
1671
gst_object_unref (sink);
1673
priv->audio_linked = (res == GST_PAD_LINK_OK);
1674
gst_element_set_state (priv->audio, BRASERO_METADATA_INITIAL_STATE);
1678
if (!strcmp (name, "video/x-raw") && !priv->video_linked) {
1679
BRASERO_UTILS_LOG ("RAW video stream found");
1681
if (!priv->video && (priv->flags & BRASERO_METADATA_FLAG_THUMBNAIL)) {
1682
/* we shouldn't error out if we can't create a video
1683
* pipeline (mostly used for snapshots) */
1684
/* FIXME: we should nevertheless tell the user what
1685
* plugin he is missing. */
1686
if (!brasero_metadata_create_video_pipeline (self)) {
1687
BRASERO_UTILS_LOG ("Impossible to create video pipeline");
1689
gst_caps_unref (caps);
1691
if (!brasero_metadata_link_dummy_pad (self, pad))
1692
brasero_metadata_error_on_pad_linking (self);
1697
sink = gst_element_get_static_pad (priv->video, "sink");
1698
if (!sink || GST_PAD_IS_LINKED (sink)) {
1699
gst_object_unref (sink);
1700
gst_caps_unref (caps);
1704
res = gst_pad_link (pad, sink);
1705
priv->video_linked = (res == GST_PAD_LINK_OK);
1706
gst_object_unref (sink);
1708
gst_element_set_state (priv->video, BRASERO_METADATA_INITIAL_STATE);
1710
BRASERO_UTILS_LOG ("Video stream link %i for %s", res, priv->info->uri);
1712
else if (!brasero_metadata_link_dummy_pad (self, pad))
1713
brasero_metadata_error_on_pad_linking (self);
1715
else if (has_video && !brasero_metadata_link_dummy_pad (self, pad))
1716
brasero_metadata_error_on_pad_linking (self);
1718
gst_caps_unref (caps);
1722
brasero_metadata_create_pipeline (BraseroMetadata *self)
1724
BraseroMetadataPrivate *priv;
1726
priv = BRASERO_METADATA_PRIVATE (self);
1728
priv->pipeline = gst_pipeline_new (NULL);
1730
priv->decode = gst_element_factory_make ("decodebin", NULL);
1731
if (priv->decode == NULL) {
1732
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1733
BRASERO_UTILS_ERROR_GENERAL,
1734
_("%s element could not be created"),
1738
g_signal_connect (G_OBJECT (priv->decode), "pad-added",
1739
G_CALLBACK (brasero_metadata_new_decoded_pad_cb),
1742
gst_bin_add (GST_BIN (priv->pipeline), priv->decode);
1744
/* the two following objects don't always run */
1745
priv->convert = gst_element_factory_make ("audioconvert", NULL);
1746
if (!priv->convert) {
1747
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1748
BRASERO_UTILS_ERROR_GENERAL,
1749
_("%s element could not be created"),
1750
"\"Audioconvert\"");
1754
priv->sink = gst_element_factory_make ("fakesink", NULL);
1755
if (priv->sink == NULL) {
1756
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1757
BRASERO_UTILS_ERROR_GENERAL,
1758
_("%s element could not be created"),
1767
brasero_metadata_set_new_uri (BraseroMetadata *self,
1770
BraseroMetadataPrivate *priv;
1773
priv = BRASERO_METADATA_PRIVATE (self);
1775
BRASERO_UTILS_LOG ("New retrieval for %s %p", uri, self);
1778
g_error_free (priv->error);
1782
brasero_metadata_info_free (priv->info);
1785
if (priv->silence) {
1786
g_free (priv->silence);
1787
priv->silence = NULL;
1790
priv->info = g_new0 (BraseroMetadataInfo, 1);
1791
priv->info->uri = g_strdup (uri);
1793
if (priv->pipeline){
1794
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
1796
gst_bin_remove (GST_BIN (priv->pipeline), priv->source);
1797
priv->source = NULL;
1801
gst_bin_remove (GST_BIN (priv->pipeline), priv->audio);
1806
gst_bin_remove (GST_BIN (priv->pipeline), priv->video);
1807
priv->snapshot = NULL;
1811
else if (!brasero_metadata_create_pipeline (self))
1814
if (!gst_uri_is_valid (uri))
1817
priv->video_linked = 0;
1818
priv->audio_linked = 0;
1819
priv->snapshot_started = 0;
1821
/* create a necessary source */
1822
priv->source = gst_element_make_from_uri (GST_URI_SRC,
1825
if (!priv->source) {
1826
priv->error = g_error_new (BRASERO_UTILS_ERROR,
1827
BRASERO_UTILS_ERROR_GENERAL,
1828
"Can't create file source");
1832
gst_bin_add (GST_BIN (priv->pipeline), priv->source);
1833
gst_element_link (priv->source, priv->decode);
1835
/* apparently we need to reconnect to the bus every time */
1837
g_source_remove (priv->watch);
1839
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
1840
priv->watch = gst_bus_add_watch (bus,
1841
(GstBusFunc) brasero_metadata_bus_messages,
1843
gst_object_unref (bus);
1849
brasero_metadata_set_uri (BraseroMetadata *self,
1850
BraseroMetadataFlag flags,
1854
GstStateChangeReturn state_change;
1855
BraseroMetadataPrivate *priv;
1857
priv = BRASERO_METADATA_PRIVATE (self);
1859
g_mutex_lock (priv->mutex);
1861
priv->flags = flags;
1862
if (!brasero_metadata_set_new_uri (self, uri)) {
1864
BRASERO_UTILS_LOG ("Failed to set new URI %s", priv->error->message);
1865
g_propagate_error (error, priv->error);
1869
brasero_metadata_info_free (priv->info);
1872
g_mutex_unlock (priv->mutex);
1877
state_change = gst_element_set_state (GST_ELEMENT (priv->pipeline),
1878
BRASERO_METADATA_INITIAL_STATE);
1880
g_mutex_unlock (priv->mutex);
1882
if (state_change == GST_STATE_CHANGE_FAILURE)
1883
brasero_metadata_stop (self);
1885
return (state_change != GST_STATE_CHANGE_FAILURE);
1889
brasero_metadata_get_info_async (BraseroMetadata *self,
1891
BraseroMetadataFlag flags)
1893
BraseroMetadataPrivate *priv;
1894
GstStateChangeReturn state_change;
1896
priv = BRASERO_METADATA_PRIVATE (self);
1898
priv->flags = flags;
1900
if (!brasero_metadata_set_new_uri (self, uri)) {
1901
g_object_ref (self);
1902
g_signal_emit (G_OBJECT (self),
1903
brasero_metadata_signals [COMPLETED_SIGNAL],
1906
g_object_unref (self);
1909
BRASERO_UTILS_LOG ("Failed to set new URI %s", priv->error->message);
1910
g_error_free (priv->error);
1916
state_change = gst_element_set_state (GST_ELEMENT (priv->pipeline),
1917
BRASERO_METADATA_INITIAL_STATE);
1919
priv->started = (state_change != GST_STATE_CHANGE_FAILURE);
1920
return priv->started;
1924
brasero_metadata_wait_cancelled (GCancellable *cancel,
1927
BRASERO_UTILS_LOG ("Thread waiting for retrieval end cancelled");
1928
g_cond_broadcast (condition);
1932
brasero_metadata_wait (BraseroMetadata *self,
1933
GCancellable *cancel)
1935
BraseroMetadataPrivate *priv;
1939
priv = BRASERO_METADATA_PRIVATE (self);
1941
BRASERO_UTILS_LOG ("Metadata lock and wait %p", self);
1943
g_mutex_lock (priv->mutex);
1945
if (!priv->started) {
1946
/* Maybe we were waiting for the lock which was held by the
1947
* finish function. That's why we check if it didn't finish in
1949
g_mutex_unlock (priv->mutex);
1953
condition = g_cond_new ();
1954
priv->conditions = g_slist_prepend (priv->conditions, condition);
1956
sig = g_signal_connect (cancel,
1958
G_CALLBACK (brasero_metadata_wait_cancelled),
1961
if (!g_cancellable_is_cancelled (cancel))
1962
g_cond_wait (condition, priv->mutex);
1964
priv->conditions = g_slist_remove (priv->conditions, condition);
1965
g_cond_free (condition);
1967
g_mutex_unlock (priv->mutex);
1969
g_signal_handler_disconnect (cancel, sig);
1973
brasero_metadata_increase_listener_number (BraseroMetadata *self)
1975
BraseroMetadataPrivate *priv;
1977
priv = BRASERO_METADATA_PRIVATE (self);
1978
g_atomic_int_inc (&priv->listeners);
1982
brasero_metadata_decrease_listener_number (BraseroMetadata *self)
1984
BraseroMetadataPrivate *priv;
1986
priv = BRASERO_METADATA_PRIVATE (self);
1987
return g_atomic_int_dec_and_test (&priv->listeners);
1991
brasero_metadata_get_uri (BraseroMetadata *self)
1993
BraseroMetadataPrivate *priv;
1995
priv = BRASERO_METADATA_PRIVATE (self);
1996
return priv->info?priv->info->uri:NULL;
2000
brasero_metadata_get_flags (BraseroMetadata *self)
2002
BraseroMetadataPrivate *priv;
2004
priv = BRASERO_METADATA_PRIVATE (self);
2009
brasero_metadata_get_result (BraseroMetadata *self,
2010
BraseroMetadataInfo *info,
2013
BraseroMetadataPrivate *priv;
2015
priv = BRASERO_METADATA_PRIVATE (self);
2019
*error = g_error_copy (priv->error);
2030
memset (info, 0, sizeof (BraseroMetadataInfo));
2031
brasero_metadata_info_copy (info, priv->info);
2036
brasero_metadata_init (BraseroMetadata *obj)
2038
BraseroMetadataPrivate *priv;
2040
priv = BRASERO_METADATA_PRIVATE (obj);
2042
priv->mutex = g_mutex_new ();
2046
brasero_metadata_finalize (GObject *object)
2048
BraseroMetadataPrivate *priv;
2051
priv = BRASERO_METADATA_PRIVATE (object);
2053
brasero_metadata_destroy_pipeline (BRASERO_METADATA (object));
2055
if (priv->silence) {
2056
g_free (priv->silence);
2057
priv->silence = NULL;
2061
g_error_free (priv->error);
2066
g_source_remove (priv->watch);
2071
brasero_metadata_info_free (priv->info);
2075
for (iter = priv->conditions; iter; iter = iter->next) {
2078
condition = iter->data;
2079
g_cond_broadcast (condition);
2080
g_cond_free (condition);
2082
g_slist_free (priv->conditions);
2083
priv->conditions = NULL;
2086
g_mutex_free (priv->mutex);
2090
G_OBJECT_CLASS (brasero_metadata_parent_class)->finalize (object);
2094
brasero_metadata_get_property (GObject *obj,
2100
BraseroMetadata *self;
2101
BraseroMetadataPrivate *priv;
2103
self = BRASERO_METADATA (obj);
2104
priv = BRASERO_METADATA_PRIVATE (self);
2108
g_object_get (G_OBJECT (priv->source), "location",
2110
g_value_set_string (value, uri);
2114
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
2120
brasero_metadata_set_property (GObject *obj,
2122
const GValue *value,
2126
BraseroMetadata *self;
2127
BraseroMetadataPrivate *priv;
2129
self = BRASERO_METADATA (obj);
2130
priv = BRASERO_METADATA_PRIVATE (self);
2134
uri = g_value_get_string (value);
2135
gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_NULL);
2137
g_object_set (G_OBJECT (priv->source),
2140
gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PAUSED);
2144
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
2150
brasero_metadata_class_init (BraseroMetadataClass *klass)
2152
GObjectClass *object_class = G_OBJECT_CLASS (klass);
2154
g_type_class_add_private (klass, sizeof (BraseroMetadataPrivate));
2156
object_class->finalize = brasero_metadata_finalize;
2157
object_class->set_property = brasero_metadata_set_property;
2158
object_class->get_property = brasero_metadata_get_property;
2160
brasero_metadata_signals[COMPLETED_SIGNAL] =
2161
g_signal_new ("completed",
2162
G_TYPE_FROM_CLASS (klass),
2164
G_STRUCT_OFFSET (BraseroMetadataClass,
2167
g_cclosure_marshal_VOID__POINTER,
2171
g_object_class_install_property (object_class,
2173
g_param_spec_string ("uri",
2174
"The uri of the song",
2175
"The uri of the song",
2177
G_PARAM_READWRITE));
2181
brasero_metadata_new (void)
2183
return BRASERO_METADATA (g_object_new (BRASERO_TYPE_METADATA, NULL));