Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
meta_data_extractor.h
Go to the documentation of this file.
1 /*
2  * Copyright © 2013 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18 
19 #ifndef GSTREAMER_META_DATA_EXTRACTOR_H_
20 #define GSTREAMER_META_DATA_EXTRACTOR_H_
21 
22 #include "../engine.h"
23 
24 #include "bus.h"
25 
26 #include <gst/gst.h>
27 
28 #include <exception>
29 #include <future>
30 
31 namespace gstreamer
32 {
34 {
35 public:
37  : pipe(gst_pipeline_new("meta_data_extractor_pipeline")),
38  decoder(gst_element_factory_make ("uridecodebin", NULL)),
39  bus(GST_ELEMENT_BUS(pipe))
40  {
41  gst_bin_add(GST_BIN(pipe), decoder);
42 
43  auto sink = gst_element_factory_make ("fakesink", NULL);
44  gst_bin_add (GST_BIN (pipe), sink);
45 
46  g_signal_connect (decoder, "pad-added", G_CALLBACK (on_new_pad), sink);
47  }
48 
50  {
51  gst_element_set_state(pipe, GST_STATE_NULL);
52  // gst_object_unref(pipe);
53  }
54 
56  {
57  if (!gst_uri_is_valid(uri.c_str()))
58  throw std::runtime_error("Invalid uri");
59 
61  std::promise<core::ubuntu::media::Track::MetaData> promise;
62  std::future<core::ubuntu::media::Track::MetaData> future{promise.get_future()};
63 
64  core::ScopedConnection on_new_message_connection
65  {
66  bus.on_new_message.connect(
67  [&](const gstreamer::Bus::Message& msg)
68  {
69  std::cout << __PRETTY_FUNCTION__ << gst_message_type_get_name(msg.type) << std::endl;
70  if (msg.type == GST_MESSAGE_TAG)
71  {
72  MetaDataExtractor::on_tag_available(msg.detail.tag, meta_data);
73  } else if (msg.type == GST_MESSAGE_ASYNC_DONE)
74  {
75  promise.set_value(meta_data);
76  }
77  })
78  };
79 
80  g_object_set(decoder, "uri", uri.c_str(), NULL);
81  gst_element_set_state(pipe, GST_STATE_PAUSED);
82 
83  if (std::future_status::ready != future.wait_for(std::chrono::seconds(2)))
84  {
85  gst_element_set_state(pipe, GST_STATE_NULL);
86  throw std::runtime_error("Problem extracting meta data for track");
87  } else
88  {
89  gst_element_set_state(pipe, GST_STATE_NULL);
90  }
91 
92  return future.get();
93  }
94 
95 private:
96  static void on_new_pad(GstElement*, GstPad* pad, GstElement* fakesink)
97  {
98  GstPad *sinkpad;
99 
100  sinkpad = gst_element_get_static_pad (fakesink, "sink");
101 
102  if (!gst_pad_is_linked (sinkpad)) {
103  if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
104  g_error ("Failed to link pads!");
105  }
106 
107  gst_object_unref (sinkpad);
108  }
109 
110  static void on_tag_available(
113  {
114  namespace media = core::ubuntu::media;
115 
116  gst_tag_list_foreach(
117  tag.tag_list,
118  [](const GstTagList *list,
119  const gchar* tag,
120  gpointer user_data)
121  {
122  (void) list;
123 
124  static const std::map<std::string, std::string> gstreamer_to_mpris_tag_lut =
125  {
126  {GST_TAG_ALBUM, media::Engine::Xesam::album()},
127  {GST_TAG_ALBUM_ARTIST, media::Engine::Xesam::album_artist()},
128  {GST_TAG_ARTIST, media::Engine::Xesam::artist()},
129  {GST_TAG_LYRICS, media::Engine::Xesam::as_text()},
130  {GST_TAG_COMMENT, media::Engine::Xesam::comment()},
131  {GST_TAG_COMPOSER, media::Engine::Xesam::composer()},
132  {GST_TAG_DATE, media::Engine::Xesam::content_created()},
133  {GST_TAG_ALBUM_VOLUME_NUMBER, media::Engine::Xesam::disc_number()},
134  {GST_TAG_GENRE, media::Engine::Xesam::genre()},
135  {GST_TAG_TITLE, media::Engine::Xesam::title()},
136  {GST_TAG_TRACK_NUMBER, media::Engine::Xesam::track_number()},
137  {GST_TAG_USER_RATING, media::Engine::Xesam::user_rating()}
138  };
139 
140  auto md = static_cast<media::Track::MetaData*>(user_data);
141  std::stringstream ss;
142 
143  switch(gst_tag_get_type(tag))
144  {
145  case G_TYPE_BOOLEAN:
146  {
147  gboolean value;
148  if (gst_tag_list_get_boolean(list, tag, &value))
149  ss << value;
150  break;
151  }
152  case G_TYPE_INT:
153  {
154  gint value;
155  if (gst_tag_list_get_int(list, tag, &value))
156  ss << value;
157  break;
158  }
159  case G_TYPE_UINT:
160  {
161  guint value;
162  if (gst_tag_list_get_uint(list, tag, &value))
163  ss << value;
164  break;
165  }
166  case G_TYPE_INT64:
167  {
168  gint64 value;
169  if (gst_tag_list_get_int64(list, tag, &value))
170  ss << value;
171  break;
172  }
173  case G_TYPE_UINT64:
174  {
175  guint64 value;
176  if (gst_tag_list_get_uint64(list, tag, &value))
177  ss << value;
178  break;
179  }
180  case G_TYPE_FLOAT:
181  {
182  gfloat value;
183  if (gst_tag_list_get_float(list, tag, &value))
184  ss << value;
185  break;
186  }
187  case G_TYPE_DOUBLE:
188  {
189  double value;
190  if (gst_tag_list_get_double(list, tag, &value))
191  ss << value;
192  break;
193  }
194  case G_TYPE_STRING:
195  {
196  gchar* value;
197  if (gst_tag_list_get_string(list, tag, &value))
198  {
199  ss << value;
200  g_free(value);
201  }
202  break;
203  }
204  default:
205  break;
206  }
207 
208  (*md).set(
209  (gstreamer_to_mpris_tag_lut.count(tag) > 0 ? gstreamer_to_mpris_tag_lut.at(tag) : tag),
210  ss.str());
211  },
212  &md);
213  }
214 
215  GstElement* pipe;
216  GstElement* decoder;
217  Bus bus;
218 };
219 }
220 
221 #endif // GSTREAMER_META_DATA_EXTRACTOR_H_
core::Signal< Message > on_new_message
Definition: bus.h:303
GstMessageType type
Definition: bus.h:181
union gstreamer::Bus::Message::Detail detail
core::ubuntu::media::Track::MetaData meta_data_for_track_with_uri(const core::ubuntu::media::Track::UriType &uri)
struct gstreamer::Bus::Message::Detail::Tag tag
std::string UriType
Definition: track.h:40