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 }