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 #include "../xesam.h"
24 
25 #include "bus.h"
26 
27 #include <gst/gst.h>
28 
29 #include <exception>
30 #include <future>
31 
32 namespace gstreamer
33 {
35 {
36 public:
37  static const std::map<std::string, std::string>& gstreamer_to_mpris_tag_lut()
38  {
39  static const std::map<std::string, std::string> lut
40  {
41  {GST_TAG_ALBUM, std::string{xesam::Album::name}},
42  {GST_TAG_ALBUM_ARTIST, std::string{xesam::AlbumArtist::name}},
43  {GST_TAG_ARTIST, std::string{xesam::Artist::name}},
44  {GST_TAG_LYRICS, std::string{xesam::AsText::name}},
45  {GST_TAG_COMMENT, std::string{xesam::Comment::name}},
46  {GST_TAG_COMPOSER, std::string{xesam::Composer::name}},
47  {GST_TAG_DATE, std::string{xesam::ContentCreated::name}},
48  {GST_TAG_ALBUM_VOLUME_NUMBER, std::string{xesam::DiscNumber::name}},
49  {GST_TAG_GENRE, std::string{xesam::Genre::name}},
50  {GST_TAG_TITLE, std::string{xesam::Title::name}},
51  {GST_TAG_TRACK_NUMBER, std::string{xesam::TrackNumber::name}},
52  {GST_TAG_USER_RATING, std::string{xesam::UserRating::name}}
53  };
54 
55  return lut;
56  }
57 
58  static void on_tag_available(
61  {
62  namespace media = core::ubuntu::media;
63 
64  gst_tag_list_foreach(
65  tag.tag_list,
66  [](const GstTagList *list,
67  const gchar* tag,
68  gpointer user_data)
69  {
70  (void) list;
71 
72  auto md = static_cast<media::Track::MetaData*>(user_data);
73  std::stringstream ss;
74 
75  switch(gst_tag_get_type(tag))
76  {
77  case G_TYPE_BOOLEAN:
78  {
79  gboolean value;
80  if (gst_tag_list_get_boolean(list, tag, &value))
81  ss << value;
82  break;
83  }
84  case G_TYPE_INT:
85  {
86  gint value;
87  if (gst_tag_list_get_int(list, tag, &value))
88  ss << value;
89  break;
90  }
91  case G_TYPE_UINT:
92  {
93  guint value;
94  if (gst_tag_list_get_uint(list, tag, &value))
95  ss << value;
96  break;
97  }
98  case G_TYPE_INT64:
99  {
100  gint64 value;
101  if (gst_tag_list_get_int64(list, tag, &value))
102  ss << value;
103  break;
104  }
105  case G_TYPE_UINT64:
106  {
107  guint64 value;
108  if (gst_tag_list_get_uint64(list, tag, &value))
109  ss << value;
110  break;
111  }
112  case G_TYPE_FLOAT:
113  {
114  gfloat value;
115  if (gst_tag_list_get_float(list, tag, &value))
116  ss << value;
117  break;
118  }
119  case G_TYPE_DOUBLE:
120  {
121  double value;
122  if (gst_tag_list_get_double(list, tag, &value))
123  ss << value;
124  break;
125  }
126  case G_TYPE_STRING:
127  {
128  gchar* value;
129  if (gst_tag_list_get_string(list, tag, &value))
130  {
131  ss << value;
132  g_free(value);
133  }
134  break;
135  }
136  default:
137  break;
138  }
139 
140  (*md).set(
141  (gstreamer_to_mpris_tag_lut().count(tag) > 0 ? gstreamer_to_mpris_tag_lut().at(tag) : tag),
142  ss.str());
143  },
144  &md);
145  }
146 
148  : pipe(gst_pipeline_new("meta_data_extractor_pipeline")),
149  decoder(gst_element_factory_make ("uridecodebin", NULL)),
150  bus(GST_ELEMENT_BUS(pipe))
151  {
152  gst_bin_add(GST_BIN(pipe), decoder);
153 
154  auto sink = gst_element_factory_make ("fakesink", NULL);
155  gst_bin_add (GST_BIN (pipe), sink);
156 
157  g_signal_connect (decoder, "pad-added", G_CALLBACK (on_new_pad), sink);
158  }
159 
161  {
162  gst_element_set_state(pipe, GST_STATE_NULL);
163  // gst_object_unref(pipe);
164  }
165 
167  {
168  if (!gst_uri_is_valid(uri.c_str()))
169  throw std::runtime_error("Invalid uri");
170 
172  std::promise<core::ubuntu::media::Track::MetaData> promise;
173  std::future<core::ubuntu::media::Track::MetaData> future{promise.get_future()};
174 
175  core::ScopedConnection on_new_message_connection
176  {
177  bus.on_new_message.connect(
178  [&](const gstreamer::Bus::Message& msg)
179  {
180  std::cout << __PRETTY_FUNCTION__ << gst_message_type_get_name(msg.type) << std::endl;
181  if (msg.type == GST_MESSAGE_TAG)
182  {
184  } else if (msg.type == GST_MESSAGE_ASYNC_DONE)
185  {
186  promise.set_value(meta_data);
187  }
188  })
189  };
190 
191  g_object_set(decoder, "uri", uri.c_str(), NULL);
192  gst_element_set_state(pipe, GST_STATE_PAUSED);
193 
194  if (std::future_status::ready != future.wait_for(std::chrono::seconds(2)))
195  {
196  gst_element_set_state(pipe, GST_STATE_NULL);
197  throw std::runtime_error("Problem extracting meta data for track");
198  } else
199  {
200  gst_element_set_state(pipe, GST_STATE_NULL);
201  }
202 
203  return future.get();
204  }
205 
206 private:
207  static void on_new_pad(GstElement*, GstPad* pad, GstElement* fakesink)
208  {
209  GstPad *sinkpad;
210 
211  sinkpad = gst_element_get_static_pad (fakesink, "sink");
212 
213  if (!gst_pad_is_linked (sinkpad)) {
214  if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
215  g_error ("Failed to link pads!");
216  }
217 
218  gst_object_unref (sinkpad);
219  }
220 
221  GstElement* pipe;
222  GstElement* decoder;
223  Bus bus;
224 };
225 }
226 
227 #endif // GSTREAMER_META_DATA_EXTRACTOR_H_
GstMessageType type
Definition: bus.h:181
Definition: bus.h:33
static const std::map< std::string, std::string > & gstreamer_to_mpris_tag_lut()
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
static void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag, core::ubuntu::media::Track::MetaData &md)
std::string UriType
Definition: track.h:40