Add the TODO file.
[dictix.git] / libdictix / dix-tag-reader.c
blob8c399826d412959ad705d838ad8da87746c699e7
1 /**
2 * Dictix / DixTagReader - dix-tag-reader.c
4 * Copyright (C) Martin Blanchard 2011 <tinram@gmx.fr>
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 2 of the License, or
9 * (at your option) any later version.
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.
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 Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <gio/gio.h>
31 #include <gst/gst.h>
32 #include <gst/pbutils/pbutils.h>
34 #include "dix-tag-reader.h"
36 enum {
37 PROP_0,
38 PROP_FILE_URI
41 struct _DixTagReaderPrivate
43 gchar *uri;
45 GstDiscoverer *discoverer;
47 GstBus *bus;
49 gchar* title;
50 gchar* codec;
51 guint64 bytes;
52 gint64 duration;
53 gint channels;
54 gint sample_rate;
55 gint bit_rate;
58 #define DIX_TAG_READER_GET_PRIVATE(obj) \
59 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), DIX_TYPE_TAG_READER, DixTagReaderPrivate))
61 G_DEFINE_TYPE (DixTagReader, dix_tag_reader, GST_TYPE_PIPELINE)
63 static void dix_tag_reader_load_tag (const GstTagList *list, const gchar *tag, gpointer *data);
65 static void
66 dix_tag_reader_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
68 DixTagReader *reader = (DixTagReader *) object;
69 DixTagReaderPrivate *priv = reader->priv;
71 switch (prop_id) {
72 case PROP_FILE_URI:
73 priv->uri = g_strdup (g_value_get_string (value));
75 break;
76 default:
77 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
81 static void
82 dix_tag_reader_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
84 DixTagReader *reader = (DixTagReader *) object;
85 DixTagReaderPrivate *priv = reader->priv;
87 switch (prop_id) {
88 case PROP_FILE_URI:
89 g_value_set_string (value, priv->uri);
91 break;
92 default:
93 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
97 static void
98 dix_tag_reader_finalize (GObject *object)
100 DixTagReader *reader = (DixTagReader *) object;
101 DixTagReaderPrivate *priv = reader->priv;
103 if (priv->discoverer != NULL) {
104 g_object_unref (G_OBJECT (priv->discoverer));
106 priv->discoverer = NULL;
108 g_free (priv->uri);
109 priv->uri = NULL;
111 if (priv->title != NULL) {
112 g_free (priv->title);
114 priv->title = NULL;
115 if (priv->codec != NULL) {
116 g_free (priv->codec);
118 priv->codec = NULL;
120 G_OBJECT_CLASS (dix_tag_reader_parent_class)->finalize (object);
123 static void
124 dix_tag_reader_class_init (DixTagReaderClass* klass)
126 GObjectClass *gobject_class = (GObjectClass *) klass;
128 gobject_class->set_property = dix_tag_reader_set_property;
129 gobject_class->get_property = dix_tag_reader_get_property;
130 gobject_class->finalize = dix_tag_reader_finalize;
132 g_object_class_install_property (gobject_class,
133 PROP_FILE_URI,
134 g_param_spec_string ("file-uri",
135 "FLAC audio file uri",
136 "Uri of the flac audio file we're about to parse",
137 NULL,
138 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
140 g_type_class_add_private (gobject_class, sizeof (DixTagReaderPrivate));
143 static void
144 dix_tag_reader_init (DixTagReader* reader)
146 DixTagReaderPrivate *priv = DIX_TAG_READER_GET_PRIVATE (reader);
147 reader->priv = priv;
148 GError *error = NULL;
150 gst_object_set_name (GST_OBJECT(reader), "DictixTagReader");
152 priv->uri = NULL;
154 priv->discoverer = gst_discoverer_new (20 * GST_SECOND, NULL);
155 if (priv->discoverer == NULL) {
156 g_warning (error->message);
157 g_error_free (error);
159 return;
162 priv->title = NULL;
163 priv->codec = NULL;
164 priv->bytes = -1;
165 priv->duration = -1;
166 priv->channels = -1;
167 priv->sample_rate = -1;
168 priv->bit_rate = -1;
171 DixTagReader*
172 dix_tag_reader_new (const gchar* uri)
174 g_return_val_if_fail ((uri != NULL), NULL);
175 if (g_str_has_suffix (uri, ".flac") == FALSE) {
176 g_warning ("TagReader only support FLAC audio file.\n");
178 return NULL;
181 return g_object_new (DIX_TYPE_TAG_READER, "file-uri", uri, NULL);
184 void
185 dix_tag_reader_load (DixTagReader *reader)
187 g_return_if_fail (DIX_IS_TAG_READER (reader));
188 DixTagReaderPrivate *priv = reader->priv;
189 GError *error = NULL;
190 /* GFile *file = NULL;*/
191 /* GstDiscovererInfo *info = NULL;*/
192 /* GstDiscovererStreamInfo *stream_info = NULL;*/
193 /* const GstTagList *tags;*/
194 /* GList *streams = NULL;*/
195 /* GstClockTime length = 0;*/
196 GstElement *source = NULL;
197 GstElement *decoder = NULL;
198 GstElement *sink = NULL;
199 GstMessage *message;
200 GstFormat format;
201 GFile *file = NULL;
202 GFileInfo *info = NULL;
203 GstPad *pad = NULL;
204 GstCaps *caps = NULL;
205 GstStructure *structure = NULL;
206 gint64 length = 0;
207 gint state;
209 if (G_UNLIKELY (priv->uri == NULL)) {
210 g_warning ("No file specified...\n");
212 return;
215 /* file = g_file_new_for_uri (priv->uri);*/
216 /* if (file != NULL) {*/
217 /* GFileInfo *info = NULL;*/
219 /* info = g_file_query_info (file,*/
220 /* G_FILE_ATTRIBUTE_STANDARD_SIZE,*/
221 /* G_FILE_QUERY_INFO_NONE,*/
222 /* NULL,*/
223 /* NULL);*/
225 /* priv->bytes = (guint64) g_file_info_get_size (info);*/
226 /* }*/
228 /* if (G_LIKELY (priv->discoverer != NULL)) {*/
229 /* info = gst_discoverer_discover_uri (priv->discoverer,*/
230 /* priv->uri,*/
231 /* &error);*/
232 /* if (error != NULL) {*/
233 /* g_warning (error->message);*/
234 /* g_error_free (error);*/
236 /* return;*/
237 /* }*/
239 /* tags = gst_discoverer_info_get_tags (info);*/
240 /* if (tags != NULL) {*/
241 /* gst_tag_list_foreach (tags,(GstTagForeachFunc) dix_tag_reader_load_tag, reader);*/
242 /* }*/
243 /* }*/
245 /* priv->duration = gst_discoverer_info_get_duration (info);*/
247 /* stream_info = gst_discoverer_info_get_stream_info (info);*/
248 /* if (stream_info != NULL) {*/
251 /* gst_discoverer_stream_info_unref (stream_info);*/
252 /* }*/
254 /* streams = gst_discoverer_info_get_audio_streams (info);*/
255 /* if (streams != NULL) {*/
256 /* priv->channels = gst_discoverer_audio_info_get_channels (streams->data);*/
257 /* priv->sample_rate = gst_discoverer_audio_info_get_sample_rate (streams->data);*/
258 /* priv->bit_rate = gst_discoverer_audio_info_get_bitrate (streams->data);*/
260 /* gst_discoverer_stream_info_list_free (streams);*/
261 /* }*/
263 if (G_LIKELY (priv->bus == NULL)) {
264 source = gst_element_factory_make ("giosrc", "DictixTagReaderSource");
265 if (source == NULL) {
266 return;
268 g_object_set (G_OBJECT (source), "location", priv->uri, NULL);
269 gst_bin_add (GST_BIN (reader), source);
271 decoder = gst_element_factory_make ("flacdec", "DictixTagReaderDecoder");
272 if (decoder == NULL) {
273 gst_object_unref (source);
275 return;
277 gst_bin_add (GST_BIN (reader), decoder);
278 gst_element_link (source, decoder);
280 sink = gst_element_factory_make ("fakesink", "DictixTagReaderSink");
281 if (sink == NULL) {
282 gst_object_unref (source);
283 gst_object_unref (decoder);
285 return;
287 gst_bin_add (GST_BIN (reader), sink);
288 gst_element_link (decoder, sink);
290 priv->bus = gst_element_get_bus (GST_ELEMENT (reader));
293 /* Go to GST_STATE_PAUSE: decoder will read metadata */
294 gst_element_set_state (GST_ELEMENT(reader), GST_STATE_PAUSED);
296 while (TRUE) {
297 GstTagList *tags = NULL;
299 message = gst_bus_timed_pop_filtered (priv->bus,
300 GST_CLOCK_TIME_NONE,
301 GST_MESSAGE_TAG | GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE);
303 if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_TAG) {
304 /* We've found an error or async is done */
305 break;
308 gst_message_parse_tag (message, &tags);
309 gst_tag_list_foreach (tags,(GstTagForeachFunc) dix_tag_reader_load_tag, reader);
311 gst_tag_list_free (tags);
312 gst_message_unref (message);
315 if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
316 gst_message_parse_error (message, &error, NULL);
317 if (error != NULL) {
318 g_warning (error->message);
320 return;
324 state = gst_element_get_state (GST_ELEMENT (reader), NULL, NULL, GST_CLOCK_TIME_NONE);
325 if (state != GST_STATE_CHANGE_SUCCESS) {
326 g_warning ("Failed going to PAUSE state while metadata reading...");
328 return;
331 gst_message_unref (message);
333 /* At this point we are shure to be in GST_STATE_PAUSE state */
334 format = GST_FORMAT_TIME;
335 if (gst_element_query_duration (sink, &format, &length) == TRUE) {
336 if (format == GST_FORMAT_TIME) {
337 priv->duration = length;
341 g_object_get (G_OBJECT (source), "file", &file, NULL);
342 if (file != NULL) {
343 info = g_file_query_info (file,
344 G_FILE_ATTRIBUTE_STANDARD_SIZE,
345 G_FILE_QUERY_INFO_NONE,
346 NULL,
347 NULL);
349 priv->bytes = (guint64) g_file_info_get_size (info);
352 pad = gst_element_get_static_pad (sink, "sink");
353 if (pad != NULL) {
354 caps = gst_pad_get_negotiated_caps (pad);
355 if (caps != NULL) {
356 structure = gst_caps_get_structure (caps, 0);
358 gst_structure_get_int (structure, "channels", &priv->channels);
359 gst_structure_get_int (structure, "rate", &priv->sample_rate);
363 gst_element_set_state (GST_ELEMENT(reader), GST_STATE_NULL);
366 gchar*
367 dix_tag_reader_get_title (DixTagReader *reader)
369 g_return_val_if_fail (DIX_IS_TAG_READER (reader), NULL);
370 DixTagReaderPrivate *priv = reader->priv;
372 return g_strdup (priv->title);
375 gchar*
376 dix_tag_reader_get_codec (DixTagReader *reader)
378 g_return_val_if_fail (DIX_IS_TAG_READER (reader), NULL);
379 DixTagReaderPrivate *priv = reader->priv;
381 return g_strdup (priv->codec);
384 guint64
385 dix_tag_reader_get_size (DixTagReader *reader)
387 g_return_val_if_fail (DIX_IS_TAG_READER (reader), 0);
388 DixTagReaderPrivate *priv = reader->priv;
390 return (gint64) priv->bytes;
393 gint64
394 dix_tag_reader_get_duration (DixTagReader *reader)
396 g_return_val_if_fail (DIX_IS_TAG_READER (reader), -1);
397 DixTagReaderPrivate *priv = reader->priv;
399 /* GST_FORMAT_TIME is nanoseconds... */
400 return priv->duration / GST_SECOND;
403 gint
404 dix_tag_reader_get_channels (DixTagReader *reader)
406 g_return_val_if_fail (DIX_IS_TAG_READER (reader), -1);
407 DixTagReaderPrivate *priv = reader->priv;
409 return priv->channels;
412 gint
413 dix_tag_reader_get_sample_rate (DixTagReader *reader)
415 g_return_val_if_fail (DIX_IS_TAG_READER (reader), -1);
416 DixTagReaderPrivate *priv = reader->priv;
418 return priv->sample_rate;
421 gint
422 dix_tag_reader_get_bit_rate (DixTagReader *reader)
424 g_return_val_if_fail (DIX_IS_TAG_READER (reader), -1);
425 DixTagReaderPrivate *priv = reader->priv;
427 return priv->bit_rate;
430 static void
431 dix_tag_reader_load_tag (const GstTagList *list, const gchar *tag, gpointer *data)
433 DixTagReader *reader = (DixTagReader *) data;
434 DixTagReaderPrivate *priv = reader->priv;
435 const GValue *value = NULL;
436 gint size = 0;
438 size = gst_tag_list_get_tag_size (list, tag);
439 if (size < 1) {
440 return;
443 value = gst_tag_list_get_value_index (list, tag, 0);
445 if (! g_strcmp0 (tag, GST_TAG_TITLE)) {
446 priv->title = g_strdup (g_value_get_string (value));
448 if (! g_strcmp0 (tag, GST_TAG_AUDIO_CODEC)) {
449 priv->codec = g_strdup (g_value_get_string (value));
451 if (! g_strcmp0 (tag, GST_TAG_BITRATE)) {
452 priv->bit_rate = (gint) g_value_get_uint (value);
454 if (! g_strcmp0 (tag, GST_TAG_NOMINAL_BITRATE)) {
455 priv->bit_rate = (gint) g_value_get_uint (value);
457 if (! g_strcmp0 (tag, GST_TAG_MAXIMUM_BITRATE)) {
458 priv->bit_rate = (gint) g_value_get_uint (value);