File indexing completed on 2024-05-12 04:55:36
0001 /** 0002 * \file gstfingerprintdecoder.cpp 0003 * Chromaprint fingerprint decoder using GStreamer. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 15 Feb 2013 0008 * 0009 * Copyright (C) 2013 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "gstfingerprintdecoder.h" 0028 #include <string.h> 0029 #include <QFileInfo> 0030 #include <QUrl> 0031 0032 /** 0033 * Constructor. 0034 * @param parent parent object 0035 */ 0036 GstFingerprintDecoder::GstFingerprintDecoder(QObject* parent) : 0037 AbstractFingerprintDecoder(parent), 0038 m_error(FingerprintCalculator::Ok), 0039 m_duration(0), m_channels(0), m_rate(0), m_gotPad(false) 0040 { 0041 gst_init(NULL, NULL); 0042 // gst_debug_set_default_threshold(GST_LEVEL_INFO); 0043 // gst_debug_set_colored(FALSE); 0044 m_loop = g_main_loop_new(NULL, FALSE); 0045 m_pipeline = gst_pipeline_new("pipeline"); 0046 m_dec = gst_element_factory_make("uridecodebin", "dec"); 0047 m_conv = gst_element_factory_make("audioconvert", "conv"); 0048 GstElement* sink = gst_element_factory_make("appsink", "sink"); 0049 0050 if (m_loop && m_pipeline && m_dec && m_conv && sink) { 0051 if (GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline))) { 0052 gst_bus_add_signal_watch(bus); 0053 g_signal_connect(bus, "message::eos", G_CALLBACK(cb_message), this); 0054 g_signal_connect(bus, "message::error", G_CALLBACK(cb_message), this); 0055 gst_object_unref(GST_OBJECT(bus)); 0056 } 0057 0058 g_signal_connect(m_dec, "pad-added", G_CALLBACK(cb_pad_added), this); 0059 g_signal_connect(m_dec, "no-more-pads", G_CALLBACK(cb_no_more_pads), this); 0060 g_signal_connect(m_dec, "unknown-type", G_CALLBACK(cb_unknown_type), this); 0061 0062 if (GstCaps* sinkcaps = gst_caps_new_simple( 0063 #if GST_CHECK_VERSION(1, 0, 0) 0064 "audio/x-raw", 0065 "format", G_TYPE_STRING, "S16LE", 0066 "layout", G_TYPE_STRING, "interleaved", 0067 "rate", G_TYPE_INT, 44100, 0068 "channels", G_TYPE_INT, 2, 0069 "channel-mask", GST_TYPE_BITMASK, (gint64)0x3, 0070 #else 0071 "audio/x-raw-int", 0072 "width", G_TYPE_INT, 16, 0073 "depth", G_TYPE_INT, 16, 0074 "signed", G_TYPE_BOOLEAN, TRUE, 0075 #endif 0076 NULL)) { 0077 g_object_set(G_OBJECT(sink), "caps", sinkcaps, NULL); 0078 gst_caps_unref(sinkcaps); 0079 } 0080 g_object_set(G_OBJECT(sink), 0081 "drop", FALSE, 0082 "max-buffers", BUFFER_SIZE, 0083 "sync", FALSE, 0084 "emit-signals", TRUE, 0085 NULL); 0086 #if GST_CHECK_VERSION(1, 0, 0) 0087 g_signal_connect(sink, "new-sample", G_CALLBACK(cb_new_buffer), this); 0088 #else 0089 g_signal_connect(sink, "new-buffer", G_CALLBACK(cb_new_buffer), this); 0090 #endif 0091 if (GstPad* pad = gst_element_get_static_pad(sink, "sink")) { 0092 g_signal_connect(pad, "notify::caps", G_CALLBACK(cb_notify_caps), this); 0093 gst_object_unref(pad); 0094 } 0095 0096 gst_bin_add_many(GST_BIN(m_pipeline), m_dec, m_conv, sink, NULL); 0097 gst_element_link_many(m_conv, sink, NULL); 0098 } else { 0099 if (m_loop) { 0100 g_main_loop_unref(m_loop); 0101 m_loop = NULL; 0102 } else { 0103 g_print("Failed to create main loop.\n"); 0104 } 0105 if (m_pipeline) { 0106 gst_object_unref(m_pipeline); 0107 m_pipeline = NULL; 0108 } else { 0109 g_print("Failed to create pipeline.\n"); 0110 } 0111 if (m_dec) { 0112 gst_object_unref(m_dec); 0113 m_dec = NULL; 0114 } else { 0115 g_print("Failed to create uridecodebin.\n"); 0116 } 0117 if (m_conv) { 0118 gst_object_unref(m_conv); 0119 m_conv = NULL; 0120 } else { 0121 g_print("Failed to create audioconvert.\n"); 0122 } 0123 if (sink) { 0124 gst_object_unref(sink); 0125 } else { 0126 g_print("Failed to create appsink.\n"); 0127 } 0128 } 0129 } 0130 0131 /** 0132 * Destructor. 0133 */ 0134 GstFingerprintDecoder::~GstFingerprintDecoder() 0135 { 0136 if (m_pipeline) { 0137 gst_element_set_state(m_pipeline, GST_STATE_NULL); 0138 gst_object_unref(m_pipeline); 0139 } 0140 if (m_loop) { 0141 g_main_loop_unref(m_loop); 0142 } 0143 } 0144 0145 void GstFingerprintDecoder::raiseError( 0146 FingerprintCalculator::Error error) 0147 { 0148 m_error = error; 0149 g_main_loop_quit(m_loop); 0150 } 0151 0152 gboolean GstFingerprintDecoder::cb_timeout(gpointer data) 0153 { 0154 GstFingerprintDecoder* self = reinterpret_cast<GstFingerprintDecoder*>(data); 0155 self->raiseError(FingerprintCalculator::Timeout); 0156 return FALSE; 0157 } 0158 0159 void GstFingerprintDecoder::cb_message(GstBus*, GstMessage* message, 0160 GstFingerprintDecoder* self) 0161 { 0162 switch (GST_MESSAGE_TYPE(message)) { 0163 case GST_MESSAGE_ERROR: { 0164 GError *err; 0165 gchar *debug; 0166 gst_message_parse_error(message, &err, &debug); 0167 g_print("Error: %s\n", err->message); 0168 g_error_free(err); 0169 g_free(debug); 0170 self->raiseError(FingerprintCalculator::DecoderError); 0171 break; 0172 } 0173 case GST_MESSAGE_EOS: 0174 // end-of-stream 0175 g_main_loop_quit(self->m_loop); 0176 break; 0177 default: 0178 break; 0179 } 0180 } 0181 0182 void GstFingerprintDecoder::cb_pad_added(GstElement*, GstPad* pad, 0183 GstFingerprintDecoder* self) 0184 { 0185 if (GstCaps* caps = 0186 #if GST_CHECK_VERSION(1, 0, 0) 0187 gst_pad_query_caps(pad, 0) 0188 #else 0189 gst_pad_get_caps(pad) 0190 #endif 0191 ) { 0192 const GstStructure* str = gst_caps_get_structure(caps, 0); 0193 const gchar* name = gst_structure_get_name(str); 0194 if (name && strncmp(name, "audio/x-raw", 11) == 0) { 0195 if (GstPad* nextpad = gst_element_get_static_pad(self->m_conv, "sink")) { 0196 if (!gst_pad_is_linked(nextpad)) { 0197 if (gst_pad_link(pad, nextpad) == GST_PAD_LINK_OK) { 0198 self->m_gotPad = true; 0199 } else { 0200 g_print("Failed to link pads\n"); 0201 } 0202 } 0203 gst_object_unref(nextpad); 0204 } 0205 } 0206 gst_caps_unref(caps); 0207 } 0208 } 0209 0210 void GstFingerprintDecoder::cb_no_more_pads(GstElement*, GstFingerprintDecoder* self) 0211 { 0212 if (!self->m_gotPad) { 0213 self->raiseError(FingerprintCalculator::NoStreamFound); 0214 } 0215 } 0216 0217 void GstFingerprintDecoder::cb_notify_caps(GstPad *pad, GParamSpec*, GstFingerprintDecoder* self) 0218 { 0219 if (GstCaps* caps = 0220 #if GST_CHECK_VERSION(1, 0, 0) 0221 gst_pad_get_current_caps(pad) 0222 #else 0223 gst_pad_get_negotiated_caps(pad) 0224 #endif 0225 ) { 0226 const GstStructure* str = gst_caps_get_structure(caps, 0); 0227 if (gst_structure_get_int(str, "channels", &self->m_channels) && 0228 gst_structure_get_int(str, "rate", &self->m_rate)) { 0229 emit self->started(self->m_rate, self->m_channels); 0230 } else { 0231 g_print("No channels/rate available\n"); 0232 } 0233 gst_caps_unref(caps); 0234 } 0235 if (GstQuery* query = gst_query_new_duration(GST_FORMAT_TIME)) { 0236 if (GstPad* peer = gst_pad_get_peer(pad)) { 0237 if (gst_pad_query(peer, query)) { 0238 GstFormat format; 0239 gint64 length; 0240 gst_query_parse_duration(query, &format, &length); 0241 if (format == GST_FORMAT_TIME) { 0242 self->m_duration = length / 1000000000; 0243 } 0244 } 0245 gst_object_unref(peer); 0246 } 0247 gst_query_unref(query); 0248 } 0249 } 0250 0251 void GstFingerprintDecoder::cb_unknown_type(GstElement*, GstPad*, GstCaps* caps, 0252 GstFingerprintDecoder* self) 0253 { 0254 bool isAudio = false; 0255 if (gchar* streaminfo = gst_caps_to_string(caps)) { 0256 isAudio = strncmp(streaminfo, "audio/", 6) == 0; 0257 g_free(streaminfo); 0258 } 0259 if (!isAudio) 0260 return; 0261 self->raiseError(FingerprintCalculator::NoCodecFound); 0262 } 0263 0264 void GstFingerprintDecoder::cb_new_buffer(GstElement* sink, GstFingerprintDecoder* self) 0265 { 0266 #if GST_CHECK_VERSION(1, 0, 0) 0267 GstSample* sample = 0; 0268 g_signal_emit_by_name(sink, "pull-sample", &sample); 0269 if (sample) { 0270 GstBuffer* buffer = gst_sample_get_buffer(sample); 0271 gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer); 0272 GstMapInfo mapinfo; 0273 ::memset(&mapinfo, 0, sizeof(mapinfo)); 0274 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ); 0275 emit self->bufferReady(QByteArray(reinterpret_cast<char*>(mapinfo.data), 0276 mapinfo.size)); 0277 gst_buffer_unmap(buffer, &mapinfo); 0278 gst_sample_unref(sample); 0279 #else 0280 GstBuffer* buffer = 0; 0281 g_signal_emit_by_name(sink, "pull-buffer", &buffer); 0282 if (buffer) { 0283 gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer); 0284 size_t len = GST_BUFFER_SIZE(buffer); 0285 guint8* data = GST_BUFFER_DATA(buffer); 0286 emit self->bufferReady(QByteArray(reinterpret_cast<char*>(data), len)); 0287 gst_buffer_unref(buffer); 0288 #endif 0289 if (self->isStopped()) { 0290 self->raiseError(FingerprintCalculator::FingerprintCalculationFailed); 0291 } 0292 if (buf_pos >= MAX_LENGTH_NS) { 0293 g_main_loop_quit(self->m_loop); 0294 } 0295 } 0296 } 0297 0298 /** 0299 * Run decoder on audio file. 0300 * @param filePath path to audio file 0301 */ 0302 void GstFingerprintDecoder::start(const QString& filePath) 0303 { 0304 AbstractFingerprintDecoder::start(filePath); 0305 if (!m_loop) { 0306 // Initialization failed 0307 m_error = FingerprintCalculator::DecoderError; 0308 emit error(m_error); 0309 return; 0310 } 0311 0312 m_error = FingerprintCalculator::Ok; 0313 m_duration = 0; 0314 m_channels = 0; 0315 m_rate = 0; 0316 m_gotPad = false; 0317 0318 QByteArray url( 0319 QUrl::fromLocalFile(QFileInfo(filePath).absoluteFilePath()).toEncoded()); 0320 g_object_set(G_OBJECT(m_dec), "uri", url.constData(), NULL); 0321 0322 gst_element_set_state(GST_ELEMENT(m_pipeline), GST_STATE_PLAYING); 0323 0324 guint timeoutFuncId = g_timeout_add(TIMEOUT_MS, cb_timeout, this); 0325 g_main_loop_run(m_loop); 0326 g_source_remove(timeoutFuncId); 0327 0328 gst_element_set_state(m_pipeline, GST_STATE_READY); 0329 if (m_error == FingerprintCalculator::Ok) { 0330 emit finished(m_duration); 0331 } else { 0332 emit error(m_error); 0333 } 0334 } 0335 0336 /** 0337 * Stop decoder. 0338 * Can be used to stop the decoder when an error is found after 0339 * getting bufferReady() data. 0340 */ 0341 void GstFingerprintDecoder::stop() 0342 { 0343 AbstractFingerprintDecoder::stop(); 0344 if (m_loop) { 0345 g_main_loop_quit(m_loop); 0346 } 0347 } 0348 0349 0350 /** 0351 * Create concrete fingerprint decoder. 0352 * @param parent parent object 0353 * @return fingerprint decoder instance. 0354 * @remarks This static method will be implemented by the concrete 0355 * fingerprint decoder which is used. 0356 */ 0357 AbstractFingerprintDecoder* 0358 AbstractFingerprintDecoder::createFingerprintDecoder(QObject* parent) { 0359 return new GstFingerprintDecoder(parent); 0360 }