First pass at Gstreamer 1.0 porting.

This at least compiles against gstreamer 1.2.
Things that work:
* Playing audio
* Automatically completing tags

Things that don't work
* Spotify
* Moodbar

Things I haven't tested
* Transcoding
This commit is contained in:
John Maguire 2013-09-25 15:42:13 +02:00
parent 88bb606082
commit 56c949815b
16 changed files with 367 additions and 230 deletions

View File

@ -66,11 +66,11 @@ pkg_check_modules(CHROMAPRINT libchromaprint)
pkg_check_modules(GIO gio-2.0)
pkg_check_modules(GLIB glib-2.0)
pkg_check_modules(GOBJECT gobject-2.0)
pkg_check_modules(GSTREAMER gstreamer-0.10)
pkg_check_modules(GSTREAMER_APP gstreamer-app-0.10)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-0.10)
pkg_check_modules(GSTREAMER_CDDA gstreamer-cdda-0.10)
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-0.10)
pkg_check_modules(GSTREAMER gstreamer-1.0)
pkg_check_modules(GSTREAMER_APP gstreamer-app-1.0)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-1.0)
#pkg_check_modules(GSTREAMER_CDDA gstreamer-cdda-0.10)
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-1.0)
pkg_check_modules(INDICATEQT indicate-qt)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)

View File

@ -91,17 +91,14 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
gst_app_src_set_callbacks(appsrc_, &callbacks, this, NULL);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
const int endianness = G_BIG_ENDIAN;
static const char* format = "S16BE";
#elif Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const int endianness = G_LITTLE_ENDIAN;
static const char* format = "S16LE";
#endif
// Set caps
GstCaps* caps = gst_caps_new_simple("audio/x-raw-int",
"endianness", G_TYPE_INT, endianness,
"signed", G_TYPE_BOOLEAN, TRUE,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16,
GstCaps* caps = gst_caps_new_simple("audio/x-raw",
"format", G_TYPE_STRING, format,
"rate", G_TYPE_INT, sample_rate,
"channels", G_TYPE_INT, channels,
NULL);
@ -123,8 +120,12 @@ void MediaPipeline::WriteData(const char* data, qint64 length) {
return;
GstBuffer* buffer = gst_buffer_new_and_alloc(length);
GstMapInfo map_info;
gst_buffer_map(buffer, &map_info, GST_MAP_WRITE);
memcpy(GST_BUFFER_DATA(buffer), data, length);
memcpy(map_info.data, data, length);
gst_buffer_unmap(buffer, &map_info);
GST_BUFFER_OFFSET(buffer) = offset_bytes_;
GST_BUFFER_TIMESTAMP(buffer) = offset_bytes_ * kNsecPerSec / byte_rate_;

View File

@ -40,7 +40,8 @@ static Level sDefaultLevel = Level_Debug;
static QMap<QString, Level>* sClassLevels = NULL;
static QIODevice* sNullDevice = NULL;
const char* kDefaultLogLevels = "GstEnginePipeline:2,*:3";
//const char* kDefaultLogLevels = "GstEnginePipeline:2,*:3";
const char* kDefaultLogLevels = "*:3";
static const char* kMessageHandlerMagic = "__logging_message__";
static const int kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);

View File

@ -89,20 +89,28 @@ static GstStaticPadTemplate src_factory
( SPECTRUM_FREQ_CAPS )
);
GST_BOILERPLATE (GstFFTWSpectrum, gst_fftwspectrum, GstElement,
GST_TYPE_ELEMENT);
G_DEFINE_TYPE(GstFFTWSpectrum, gst_fftwspectrum, GST_TYPE_ELEMENT);
static void gst_fftwspectrum_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_fftwspectrum_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static gboolean gst_fftwspectrum_sink_event(
GstPad* pad, GstObject* parent, GstEvent* event);
static gboolean gst_fftwspectrum_src_event(
GstPad* pad, GstObject* parent, GstEvent* event);
static gboolean gst_fftwspectrum_src_query(
GstPad* pad, GstObject* parent, GstQuery* query);
static gboolean gst_fftwspectrum_sink_query(
GstPad* pad, GstObject* parent, GstQuery* query);
static gboolean gst_fftwspectrum_set_sink_caps (GstPad *pad, GstCaps *caps);
static gboolean gst_fftwspectrum_set_src_caps (GstPad *pad, GstCaps *caps);
static void gst_fftwspectrum_fixatecaps (GstPad *pad, GstCaps *caps);
static GstCaps *gst_fftwspectrum_getcaps (GstPad *pad);
static GstFlowReturn gst_fftwspectrum_chain (GstPad *pad, GstBuffer *buf);
static GstFlowReturn gst_fftwspectrum_chain(
GstPad *pad, GstObject* object, GstBuffer *buf);
static GstStateChangeReturn gst_fftwspectrum_change_state (GstElement *element,
GstStateChange transition);
@ -115,25 +123,6 @@ static GstStateChangeReturn gst_fftwspectrum_change_state (GstElement *element,
/***************************************************************/
static void
gst_fftwspectrum_base_init (gpointer gclass)
{
static GstElementDetails element_details =
{
"FFTW-based Fourier transform",
"Filter/Converter/Spectrum",
"Convert a raw audio stream into a frequency spectrum",
"Joe Rabinoff <bobqwatson@yahoo.com>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &element_details);
}
/* initialize the plugin's class */
static void
gst_fftwspectrum_class_init (GstFFTWSpectrumClass * klass)
@ -164,6 +153,18 @@ gst_fftwspectrum_class_init (GstFFTWSpectrumClass * klass)
gstelement_class->change_state
= GST_DEBUG_FUNCPTR (gst_fftwspectrum_change_state);
gst_element_class_add_pad_template (GST_ELEMENT_CLASS(klass),
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (GST_ELEMENT_CLASS(klass),
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_static_metadata(
GST_ELEMENT_CLASS(klass),
"FFTW-based Fourier transform",
"Filter/Converter/Spectrum",
"Convert a raw audio stream into a frequency spectrum",
"Joe Rabinoff <bobqwatson@yahoo.com>");
}
/* initialize the new element
@ -172,30 +173,28 @@ gst_fftwspectrum_class_init (GstFFTWSpectrumClass * klass)
* initialize structure
*/
static void
gst_fftwspectrum_init (GstFFTWSpectrum * conv,
GstFFTWSpectrumClass * gclass)
gst_fftwspectrum_init (GstFFTWSpectrum * conv)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (conv);
GstElementClass* klass =
G_TYPE_INSTANCE_GET_CLASS(conv, GST_ELEMENT_TYPE, GstElementClass);
conv->sinkpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_setcaps_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_set_sink_caps));
gst_pad_set_getcaps_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_getcaps));
gst_pad_set_chain_function (conv->sinkpad,
gst_pad_set_event_function(conv->sinkpad, gst_fftwspectrum_sink_event);
gst_pad_set_query_function(conv->srcpad, gst_fftwspectrum_src_query);
gst_pad_set_chain_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_chain));
conv->srcpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_set_setcaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_set_src_caps));
gst_pad_set_getcaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_getcaps));
gst_pad_set_fixatecaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_fixatecaps));
gst_pad_set_event_function(conv->srcpad, gst_fftwspectrum_src_event);
gst_pad_set_query_function(conv->sinkpad, gst_fftwspectrum_sink_query);
//gst_pad_set_fixatecaps_function (conv->srcpad,
// GST_DEBUG_FUNCPTR (gst_fftwspectrum_fixatecaps));
gst_element_add_pad (GST_ELEMENT (conv), conv->sinkpad);
@ -205,7 +204,7 @@ gst_fftwspectrum_init (GstFFTWSpectrum * conv,
conv->rate = 0;
conv->size = 0;
conv->step = 0;
/* These are set when we change to READY */
conv->fftw_in = NULL;
conv->fftw_out = NULL;
@ -223,6 +222,65 @@ gst_fftwspectrum_init (GstFFTWSpectrum * conv,
conv->hi_q = HIQUALITY_DEFAULT;
}
static gboolean
gst_fftwspectrum_sink_event(GstPad* pad, GstObject* parent, GstEvent* event)
{
GstFFTWSpectrum* conv = GST_FFTWSPECTRUM(parent);
switch (GST_EVENT_TYPE(event)) {
case GST_EVENT_CAPS: {
GstCaps* caps = NULL;
gst_event_parse_caps(event, &caps);
gst_fftwspectrum_set_sink_caps(pad, caps);
return gst_pad_push_event(conv->srcpad, event);
}
default:
return gst_pad_event_default(pad, parent, event);
}
}
static gboolean
gst_fftwspectrum_src_event(GstPad* pad, GstObject* parent, GstEvent* event)
{
switch (GST_EVENT_TYPE(event)) {
case GST_EVENT_CAPS: {
GstCaps* caps = NULL;
gst_event_parse_caps(event, &caps);
gst_fftwspectrum_set_src_caps(pad, caps);
}
// FALLTHROUGH
default:
return gst_pad_event_default(pad, parent, event);
}
}
static gboolean
gst_fftwspectrum_src_query(GstPad* pad, GstObject* parent, GstQuery* query)
{
switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_CAPS: {
GstCaps* caps = gst_fftwspectrum_getcaps(pad);
gst_pad_set_caps(pad, caps);
}
// FALLTHROUGH
default:
return gst_pad_query_default(pad, parent, query);
}
}
static gboolean
gst_fftwspectrum_sink_query(GstPad* pad, GstObject* parent, GstQuery* query)
{
switch (GST_QUERY_TYPE(query)) {
case GST_QUERY_CAPS: {
GstCaps* caps = gst_fftwspectrum_getcaps(pad);
gst_pad_set_caps(pad, caps);
}
// FALLTHROUGH
default:
return gst_pad_query_default(pad, parent, query);
}
}
static void
gst_fftwspectrum_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
@ -362,7 +420,7 @@ gst_fftwspectrum_set_sink_caps (GstPad * pad, GstCaps * caps)
/* Fixate the source caps with the given rate */
gst_caps_set_simple (newsrccaps, "rate", G_TYPE_INT, rate, NULL);
gst_pad_fixate_caps (conv->srcpad, newsrccaps);
//gst_pad_fixate_caps (conv->srcpad, newsrccaps);
conv->rate = rate;
res = gst_pad_set_caps (conv->srcpad, newsrccaps);
if (!res)
@ -515,9 +573,10 @@ gst_fftwspectrum_change_state (GstElement * element,
break;
}
res = parent_class->change_state (element, transition);
res = GST_ELEMENT_CLASS(gst_fftwspectrum_parent_class)
->change_state(element, transition);
switch (transition)
switch (transition)
{
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
@ -545,15 +604,20 @@ gst_fftwspectrum_change_state (GstElement * element,
static void
push_samples (GstFFTWSpectrum *conv, GstBuffer *buf)
{
gint newsamples = GST_BUFFER_SIZE (buf) / sizeof (gdouble);
GstMapInfo map;
gst_buffer_map(buf, &map, GST_MAP_READ);
gint newsamples = map.size / sizeof (gdouble);
gint oldsamples = conv->numsamples;
conv->numsamples += newsamples;
conv->samples = g_realloc (conv->samples, conv->numsamples * sizeof (gdouble));
memcpy (&conv->samples[oldsamples], GST_BUFFER_DATA (buf),
memcpy (&conv->samples[oldsamples], map.data,
newsamples * sizeof (gdouble));
/* GST_LOG ("Added %d samples", newsamples); */
gst_buffer_unmap(buf, &map);
}
/* This basically does the opposite of push_samples, but takes samples
@ -586,45 +650,78 @@ shift_samples (GstFFTWSpectrum *conv, gint toshift)
* by conv->step.
*/
static GstFlowReturn
gst_fftwspectrum_chain (GstPad * pad, GstBuffer * buf)
gst_fftwspectrum_chain(GstPad* pad, GstObject* object, GstBuffer* buf)
{
GstFFTWSpectrum *conv;
GstFFTWSpectrum *conv = GST_FFTWSPECTRUM(object);
GstBuffer *outbuf;
GstFlowReturn res = GST_FLOW_OK;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
push_samples (conv, buf);
gst_buffer_unref (buf);
GstQuery* query = gst_query_new_allocation(gst_pad_get_current_caps(pad), TRUE);
if (!gst_pad_peer_query(pad, query)) {
// Query failed, not a problem, we use the query defaults.
}
GstBufferPool* pool = NULL;
guint size = 0;
guint min = 0;
guint max = 0;
if (gst_query_get_n_allocation_pools(query) > 0) {
gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min, &max);
}
if (pool == NULL) {
pool = gst_buffer_pool_new();
}
GstStructure* config = gst_buffer_pool_get_config(pool);
gst_buffer_pool_config_set_params(
config, gst_pad_get_current_caps(pad), size, min, max);
gst_buffer_pool_set_config(pool, config);
gst_buffer_pool_set_active(pool, TRUE);
while (conv->numsamples >= MAX (conv->size, conv->step))
{
res = gst_pad_alloc_buffer_and_set_caps
(conv->srcpad, conv->offset, OUTPUT_SIZE (conv),
GST_PAD_CAPS(conv->srcpad), &outbuf);
/*
res = gst_pad_alloc_buffer_and_set_caps(
conv->srcpad,
conv->offset,
OUTPUT_SIZE(conv),
GST_PAD_CAPS(conv->srcpad),
&outbuf);
*/
res = gst_buffer_pool_acquire_buffer(pool, &outbuf, NULL);
if (res != GST_FLOW_OK)
break;
GST_BUFFER_SIZE (outbuf) = OUTPUT_SIZE (conv);
break;
gst_buffer_set_size(outbuf, OUTPUT_SIZE(conv));
GST_BUFFER_OFFSET (outbuf) = conv->offset;
GST_BUFFER_OFFSET_END (outbuf) = conv->offset + conv->step;
GST_BUFFER_TIMESTAMP (outbuf) = conv->timestamp;
GST_BUFFER_DURATION (outbuf)
= gst_util_uint64_scale_int (GST_SECOND, conv->step, conv->rate);
GST_BUFFER_DURATION (outbuf) =
gst_util_uint64_scale_int (GST_SECOND, conv->step, conv->rate);
/* Do the Fourier transform */
memcpy (conv->fftw_in, conv->samples, conv->size * sizeof (double));
fftw_execute (conv->fftw_plan);
{ /* Normalize */
gint i;
gfloat root = sqrtf (conv->size);
for (i = 0; i < 2*(conv->size/2+1); ++i)
conv->fftw_out[i] /= root;
gint i;
gfloat root = sqrtf (conv->size);
for (i = 0; i < 2*(conv->size/2+1); ++i) {
conv->fftw_out[i] /= root;
}
}
memcpy (GST_BUFFER_DATA (outbuf), conv->fftw_out, OUTPUT_SIZE (conv));
GstMapInfo map;
gst_buffer_map(outbuf, &map, GST_MAP_WRITE);
memcpy (map.data, conv->fftw_out, OUTPUT_SIZE (conv));
gst_buffer_unmap(outbuf, &map);
res = gst_pad_push (conv->srcpad, outbuf);
shift_samples (conv, conv->step);
if (res != GST_FLOW_OK)

View File

@ -100,8 +100,7 @@ static GstStaticPadTemplate src_factory
)
);
GST_BOILERPLATE (GstMoodbar, gst_moodbar, GstElement,
GST_TYPE_ELEMENT);
G_DEFINE_TYPE(GstMoodbar, gst_moodbar, GST_TYPE_ELEMENT);
static void gst_moodbar_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -109,9 +108,11 @@ static void gst_moodbar_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static gboolean gst_moodbar_set_sink_caps (GstPad *pad, GstCaps *caps);
static gboolean gst_moodbar_sink_event (GstPad *pad, GstEvent *event);
static gboolean gst_moodbar_sink_event (
GstPad *pad, GstObject *parent, GstEvent *event);
static GstFlowReturn gst_moodbar_chain (GstPad *pad, GstBuffer *buf);
static GstFlowReturn gst_moodbar_chain (
GstPad *pad, GstObject *object, GstBuffer *buf);
static GstStateChangeReturn gst_moodbar_change_state (GstElement *element,
GstStateChange transition);
@ -143,26 +144,6 @@ static const guint bark_bands[24]
/* GObject boilerplate stuff */
/***************************************************************/
static void
gst_moodbar_base_init (gpointer gclass)
{
static GstElementDetails element_details =
{
"Moodbar analyzer",
"Filter/Converter/Moodbar",
"Convert a spectrum into a stream of (uchar) rgb triples representing its \"mood\"",
"Joe Rabinoff <bobqwatson@yahoo.com>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &element_details);
}
/* initialize the plugin's class */
static void
gst_moodbar_class_init (GstMoodbarClass * klass)
@ -178,16 +159,28 @@ gst_moodbar_class_init (GstMoodbarClass * klass)
g_object_class_install_property (gobject_class, ARG_HEIGHT,
g_param_spec_int ("height", "Image height",
"The height of the resulting raw image",
1, G_MAXINT32, HEIGHT_DEFAULT, G_PARAM_READWRITE));
"The height of the resulting raw image",
1, G_MAXINT32, HEIGHT_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_MAX_WIDTH,
g_param_spec_int ("max-width", "Image maximum width",
"The maximum width of the resulting raw image, or 0 for no rescaling",
0, G_MAXINT32, MAX_WIDTH_DEFAULT, G_PARAM_READWRITE));
"The maximum width of the resulting raw image, or 0 for no rescaling",
0, G_MAXINT32, MAX_WIDTH_DEFAULT, G_PARAM_READWRITE));
gstelement_class->change_state
= GST_DEBUG_FUNCPTR (gst_moodbar_change_state);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_static_metadata(
gstelement_class,
"Moodbar analyzer",
"Filter/Converter/Moodbar",
"Convert a spectrum into a stream of (uchar) rgb triples representing its \"mood\"",
"Joe Rabinoff <bobqwatson@yahoo.com>");
}
/* initialize the new element
@ -196,19 +189,17 @@ gst_moodbar_class_init (GstMoodbarClass * klass)
* initialize structure
*/
static void
gst_moodbar_init (GstMoodbar *mood, GstMoodbarClass *gclass)
gst_moodbar_init (GstMoodbar *mood)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (mood);
mood->sinkpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_setcaps_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_set_sink_caps));
gst_pad_set_event_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_sink_event));
GST_DEBUG_FUNCPTR (gst_moodbar_sink_event));
gst_pad_set_chain_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_chain));
GST_DEBUG_FUNCPTR (gst_moodbar_chain));
mood->srcpad =
gst_pad_new_from_template
@ -222,7 +213,7 @@ gst_moodbar_init (GstMoodbar *mood, GstMoodbarClass *gclass)
mood->rate = 0;
mood->size = 0;
mood->barkband_table = NULL;
/* These are allocated when we change to PAUSED */
mood->r = NULL;
mood->g = NULL;
@ -240,7 +231,7 @@ static void gst_moodbar_set_property (GObject *object, guint prop_id,
{
GstMoodbar *mood = GST_MOODBAR (object);
switch (prop_id)
switch (prop_id)
{
case ARG_HEIGHT:
mood->height = (guint) g_value_get_int (value);
@ -252,7 +243,7 @@ static void gst_moodbar_set_property (GObject *object, guint prop_id,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
@ -352,16 +343,19 @@ gst_moodbar_set_sink_caps (GstPad *pad, GstCaps *caps)
static gboolean
gst_moodbar_sink_event (GstPad *pad, GstEvent *event)
gst_moodbar_sink_event (GstPad *pad, GstObject *parent, GstEvent *event)
{
GstMoodbar *mood;
GstMoodbar *mood = GST_MOODBAR(parent);
gboolean res = TRUE;
mood = GST_MOODBAR (gst_pad_get_parent (pad));
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
gst_moodbar_finish (mood);
} else if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) {
GstCaps* caps = NULL;
gst_event_parse_caps(event, &caps);
gst_moodbar_set_sink_caps(pad, caps);
}
res = gst_pad_push_event (mood->srcpad, event);
gst_object_unref (mood);
@ -397,7 +391,8 @@ gst_moodbar_change_state (GstElement *element, GstStateChange transition)
break;
}
res = parent_class->change_state (element, transition);
res = GST_ELEMENT_CLASS(gst_moodbar_parent_class)
->change_state (element, transition);
switch (transition)
{
@ -457,27 +452,31 @@ allocate_another_frame (GstMoodbar *mood)
* once we receive an EOS signal.
*/
static GstFlowReturn
gst_moodbar_chain (GstPad *pad, GstBuffer *buf)
gst_moodbar_chain (GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstMoodbar *mood = GST_MOODBAR (gst_pad_get_parent (pad));
GstMoodbar *mood = GST_MOODBAR (parent);
guint i;
gdouble amplitudes[24], rgb[3] = {0.f, 0.f, 0.f};
gdouble *out, real, imag;
guint numfreqs = NUMFREQS (mood);
if (GST_BUFFER_SIZE (buf) != numfreqs * sizeof (gdouble) * 2)
GstMapInfo map;
gst_buffer_map(buf, &map, GST_MAP_READ);
if (map.size != numfreqs * sizeof (gdouble) * 2)
{
gst_buffer_unmap(buf, &map);
gst_object_unref (mood);
return GST_FLOW_ERROR;
}
out = (gdouble *) GST_BUFFER_DATA (buf);
out = (gdouble *) map.data;
if (!allocate_another_frame (mood))
return GST_FLOW_ERROR;
/* Calculate total amplitudes for the different bark bands */
for (i = 0; i < 24; ++i)
amplitudes[i] = 0.f;
@ -501,6 +500,7 @@ gst_moodbar_chain (GstPad *pad, GstBuffer *buf)
mood->g[mood->numframes] = rgb[1];
mood->b[mood->numframes] = rgb[2];
gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
gst_object_unref (mood);
@ -624,9 +624,12 @@ gst_moodbar_finish (GstMoodbar *mood)
(output_width * mood->height * 3 * sizeof (guchar));
if (!buf)
return;
GstMapInfo map;
gst_buffer_map(buf, &map, GST_MAP_READ);
/* Don't set the timestamp, duration, etc. since it's irrelevant */
GST_BUFFER_OFFSET (buf) = 0;
data = (guchar *) GST_BUFFER_DATA (buf);
map.memory->offset = 0;
data = (guchar *) map.data;
gdouble r, g, b;
guint i, j, n;
@ -634,40 +637,43 @@ gst_moodbar_finish (GstMoodbar *mood)
for (line = 0; line < mood->height; ++line)
{
for (i = 0; i < output_width; ++i)
{
r = 0.f; g = 0.f; b = 0.f;
start = i * mood->numframes / output_width;
end = (i + 1) * mood->numframes / output_width;
if ( start == end )
end = start + 1;
{
r = 0.f; g = 0.f; b = 0.f;
start = i * mood->numframes / output_width;
end = (i + 1) * mood->numframes / output_width;
if ( start == end )
end = start + 1;
for( j = start; j < end; j++ )
{
r += mood->r[j] * 255.f;
g += mood->g[j] * 255.f;
b += mood->b[j] * 255.f;
}
for( j = start; j < end; j++ )
{
r += mood->r[j] * 255.f;
g += mood->g[j] * 255.f;
b += mood->b[j] * 255.f;
}
n = end - start;
n = end - start;
*(data++) = (guchar) (r / ((gdouble) n));
*(data++) = (guchar) (g / ((gdouble) n));
*(data++) = (guchar) (b / ((gdouble) n));
}
*(data++) = (guchar) (r / ((gdouble) n));
*(data++) = (guchar) (g / ((gdouble) n));
*(data++) = (guchar) (b / ((gdouble) n));
}
}
{ /* Now we (finally) know the width of the image we're pushing */
GstCaps *caps = gst_caps_copy (gst_pad_get_caps (mood->srcpad));
GstCaps *caps = gst_caps_copy (gst_pad_get_current_caps (mood->srcpad));
gboolean res;
gst_caps_set_simple (caps, "width", G_TYPE_INT, output_width, NULL);
gst_caps_set_simple (caps, "height", G_TYPE_INT, mood->height, NULL);
res = gst_pad_set_caps (mood->srcpad, caps);
/*
if (res)
gst_buffer_set_caps (buf, caps);
*/
gst_caps_unref (caps);
if (!res)
return;
}
gst_pad_push (mood->srcpad, buf);
gst_buffer_unmap(buf, &map);
}

View File

@ -122,7 +122,7 @@ SongLoader::Result SongLoader::LoadLocalPartial(const QString& filename) {
SongLoader::Result SongLoader::LoadAudioCD() {
#ifdef HAVE_AUDIOCD
// Create gstreamer cdda element
GstElement* cdda = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
GstElement* cdda = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL, NULL);
if (cdda == NULL) {
qLog(Error) << "Error while creating CDDA GstElement";
return Error;
@ -460,7 +460,7 @@ SongLoader::Result SongLoader::LoadRemote() {
// Create the source element automatically based on the URL
GstElement* source = gst_element_make_from_uri(
GST_URI_SRC, url_.toEncoded().constData(), NULL);
GST_URI_SRC, url_.toEncoded().constData(), NULL, NULL);
if (!source) {
qLog(Warning) << "Couldn't create gstreamer source element for" << url_.toString();
return Error;
@ -476,12 +476,13 @@ SongLoader::Result SongLoader::LoadRemote() {
// Connect callbacks
GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline.get()));
CHECKED_GCONNECT(typefind, "have-type", &TypeFound, this);
gst_bus_set_sync_handler(bus, BusCallbackSync, this);
gst_bus_set_sync_handler(bus, BusCallbackSync, this, NULL);
gst_bus_add_watch(bus, BusCallback, this);
// Add a probe to the sink so we can capture the data if it's a playlist
GstPad* pad = gst_element_get_static_pad(fakesink, "sink");
gst_pad_add_buffer_probe(pad, G_CALLBACK(DataReady), this);
gst_pad_add_probe(
pad, GST_PAD_PROBE_TYPE_BUFFER, &DataReady, this, NULL);
gst_object_unref(pad);
// Start "playing"
@ -511,16 +512,21 @@ void SongLoader::TypeFound(GstElement*, uint, GstCaps* caps, void* self) {
instance->StopTypefindAsync(true);
}
gboolean SongLoader::DataReady(GstPad*, GstBuffer* buf, void* self) {
SongLoader* instance = static_cast<SongLoader*>(self);
GstPadProbeReturn SongLoader::DataReady(
GstPad*, GstPadProbeInfo* info, gpointer self) {
SongLoader* instance = reinterpret_cast<SongLoader*>(self);
if (instance->state_ == Finished)
return true;
return GST_PAD_PROBE_OK;
GstBuffer* buffer = gst_pad_probe_info_get_buffer(info);
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_READ);
// Append the data to the buffer
instance->buffer_.append(reinterpret_cast<const char*>(GST_BUFFER_DATA(buf)),
GST_BUFFER_SIZE(buf));
instance->buffer_.append(reinterpret_cast<const char*>(map.data), map.size);
qLog(Debug) << "Received total" << instance->buffer_.size() << "bytes";
gst_buffer_unmap(buffer, &map);
if (instance->state_ == WaitingForMagic &&
(instance->buffer_.size() >= PlaylistParser::kMagicSize ||
@ -529,7 +535,7 @@ gboolean SongLoader::DataReady(GstPad*, GstBuffer* buf, void* self) {
instance->MagicReady();
}
return true;
return GST_PAD_PROBE_OK;
}
gboolean SongLoader::BusCallback(GstBus*, GstMessage* msg, gpointer self) {

View File

@ -100,7 +100,7 @@ private:
// GStreamer callbacks
static void TypeFound(GstElement* typefind, uint probability, GstCaps* caps, void* self);
static gboolean DataReady(GstPad*, GstBuffer* buf, void* self);
static GstPadProbeReturn DataReady(GstPad*, GstPadProbeInfo* buf, gpointer self);
static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage*, gpointer);
static gboolean BusCallback(GstBus*, GstMessage*, gpointer);

View File

@ -200,24 +200,28 @@ void GstEngine::UpdateScope() {
typedef Engine::Scope::value_type sample_type;
// determine the number of channels
/*
GstStructure* structure = gst_caps_get_structure(
GST_BUFFER_CAPS(latest_buffer_), 0);
*/
int channels = 2;
gst_structure_get_int(structure, "channels", &channels);
//gst_structure_get_int(structure, "channels", &channels);
// scope does not support >2 channels
if (channels > 2)
return;
const sample_type* source = reinterpret_cast<sample_type*>(
GST_BUFFER_DATA(latest_buffer_));
GstMapInfo map;
gst_buffer_map(latest_buffer_, &map, GST_MAP_READ);
const sample_type* source = reinterpret_cast<sample_type*>(map.data);
sample_type* dest = scope_.data();
const int bytes = qMin(
static_cast<Engine::Scope::size_type>(GST_BUFFER_SIZE(latest_buffer_)),
static_cast<Engine::Scope::size_type>(map.size),
scope_.size() * sizeof(sample_type));
memcpy(dest, source, bytes);
gst_buffer_unmap(latest_buffer_, &map);
gst_buffer_unref(latest_buffer_);
latest_buffer_ = NULL;
}
@ -636,19 +640,21 @@ GstEngine::PluginDetailsList
PluginDetailsList ret;
GstRegistry* registry = gst_registry_get_default();
GstRegistry* registry = gst_registry_get();
GList* const features =
gst_registry_get_feature_list(registry, GST_TYPE_ELEMENT_FACTORY);
GList* p = features;
while (p) {
GstElementFactory* factory = GST_ELEMENT_FACTORY(p->data);
if (QString(factory->details.klass).contains(classname)) {
if (QString(gst_element_factory_get_klass(factory)).contains(classname)) {
PluginDetails details;
details.name = QString::fromUtf8(GST_PLUGIN_FEATURE_NAME(p->data));
details.long_name = QString::fromUtf8(factory->details.longname);
details.description = QString::fromUtf8(factory->details.description);
details.author = QString::fromUtf8(factory->details.author);
details.name = QString::fromUtf8(GST_OBJECT_NAME(p->data));
details.long_name =
QString::fromUtf8(gst_element_factory_get_longname(factory));
details.description =
QString::fromUtf8(gst_element_factory_get_description(factory));
details.author = QString::fromUtf8(gst_element_factory_get_author(factory));
ret << details;
}
p = g_list_next(p);

View File

@ -285,7 +285,8 @@ bool GstEnginePipeline::Init() {
// We do it here because we want pre-equalized and pre-volume samples
// so that our visualization are not be affected by them.
pad = gst_element_get_static_pad(event_probe, "src");
gst_pad_add_event_probe(pad, G_CALLBACK(EventHandoffCallback), this);
gst_pad_add_probe(
pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, &EventHandoffCallback, this, NULL);
gst_object_unref(pad);
// Configure the fakesink properly
@ -296,7 +297,7 @@ bool GstEnginePipeline::Init() {
int last_band_frequency = 0;
for (int i=0 ; i<kEqBandCount ; ++i) {
GstObject* band = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), i);
GstObject* band = GST_OBJECT(gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), i));
const float frequency = kEqBandFrequencies[i];
const float bandwidth = frequency - last_band_frequency;
@ -329,12 +330,14 @@ bool GstEnginePipeline::Init() {
// Create the caps to put in each path in the tee. The scope path gets 16-bit
// ints and the audiosink path gets float32.
GstCaps* caps16 = gst_caps_new_simple ("audio/x-raw-int",
"width", G_TYPE_INT, 16,
"signed", G_TYPE_BOOLEAN, true,
GstCaps* caps16 = gst_caps_new_simple (
"audio/x-raw",
"format", G_TYPE_STRING, "S16LE",
NULL);
GstCaps* caps32 = gst_caps_new_simple ("audio/x-raw-float",
"width", G_TYPE_INT, 32,
GstCaps* caps32 = gst_caps_new_simple (
"audio/x-raw",
"format", G_TYPE_STRING, "F32LE",
NULL);
if (mono_playback_) {
gst_caps_set_simple(caps32, "channels", G_TYPE_INT, 1, NULL);
@ -347,8 +350,8 @@ bool GstEnginePipeline::Init() {
gst_caps_unref(caps32);
// Link the outputs of tee to the queues on each path.
gst_pad_link(gst_element_get_request_pad(tee, "src%d"), gst_element_get_static_pad(probe_queue, "sink"));
gst_pad_link(gst_element_get_request_pad(tee, "src%d"), gst_element_get_static_pad(audio_queue, "sink"));
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), gst_element_get_static_pad(probe_queue, "sink"));
gst_pad_link(gst_element_get_request_pad(tee, "src_%u"), gst_element_get_static_pad(audio_queue, "sink"));
// Link replaygain elements if enabled.
if (rg_enabled_) {
@ -361,8 +364,9 @@ bool GstEnginePipeline::Init() {
volume_, audioscale_, convert, audiosink_, NULL);
// Add probes and handlers.
gst_pad_add_buffer_probe(gst_element_get_static_pad(probe_converter, "src"), G_CALLBACK(HandoffCallback), this);
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this);
gst_pad_add_probe(gst_element_get_static_pad(probe_converter, "src"), GST_PAD_PROBE_TYPE_BUFFER, &HandoffCallback, this, NULL);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this, NULL);
bus_cb_id_ = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);
MaybeLinkDecodeToAudio();
@ -421,7 +425,8 @@ bool GstEnginePipeline::InitFromUrl(const QUrl &url, qint64 end_nanosec) {
GstEnginePipeline::~GstEnginePipeline() {
if (pipeline_) {
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL, NULL);
g_source_remove(bus_cb_id_);
gst_element_set_state(pipeline_, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(pipeline_));
@ -505,12 +510,7 @@ void GstEnginePipeline::StreamStatusMessageReceived(GstMessage* msg) {
const GValue* val = gst_message_get_stream_status_object(msg);
if (G_VALUE_TYPE(val) == GST_TYPE_TASK) {
GstTask* task = static_cast<GstTask*>(g_value_get_object(val));
GstTaskThreadCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.enter_thread = TaskEnterCallback;
gst_task_set_thread_callbacks(task, &callbacks, this, NULL);
gst_task_set_enter_callback(task, &TaskEnterCallback, this, NULL);
}
}
}
@ -666,8 +666,10 @@ void GstEnginePipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer self)
}
}
bool GstEnginePipeline::HandoffCallback(GstPad*, GstBuffer* buf, gpointer self) {
GstPadProbeReturn GstEnginePipeline::HandoffCallback(
GstPad*, GstPadProbeInfo* info, gpointer self) {
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
GstBuffer* buf = gst_pad_probe_info_get_buffer(info);
QList<BufferConsumer*> consumers;
{
@ -724,20 +726,22 @@ bool GstEnginePipeline::HandoffCallback(GstPad*, GstBuffer* buf, gpointer self)
instance->last_buffer_offset_ = GST_BUFFER_OFFSET(buf);
return true;
return GST_PAD_PROBE_OK;
}
bool GstEnginePipeline::EventHandoffCallback(GstPad*, GstEvent* e, gpointer self) {
GstPadProbeReturn GstEnginePipeline::EventHandoffCallback(
GstPad*, GstPadProbeInfo* info, gpointer self) {
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
GstEvent* e = gst_pad_probe_info_get_event(info);
qLog(Debug) << instance->id() << "event" << GST_EVENT_TYPE_NAME(e);
if (GST_EVENT_TYPE(e) == GST_EVENT_NEWSEGMENT && !instance->segment_start_received_) {
if (GST_EVENT_TYPE(e) == GST_EVENT_SEGMENT && !instance->segment_start_received_) {
// The segment start time is used to calculate the proper offset of data
// buffers from the start of the stream
gint64 start = 0;
gst_event_parse_new_segment(e, NULL, NULL, NULL, &start, NULL, NULL);
instance->segment_start_ = start;
const GstSegment* segment = NULL;
gst_event_parse_segment(e, &segment);
instance->segment_start_ = segment->start;
instance->segment_start_received_ = true;
if (instance->emit_track_ended_on_segment_start_) {
@ -748,7 +752,7 @@ bool GstEnginePipeline::EventHandoffCallback(GstPad*, GstEvent* e, gpointer self
}
}
return true;
return GST_PAD_PROBE_OK;
}
void GstEnginePipeline::SourceDrainedCallback(GstURIDecodeBin* bin, gpointer self) {
@ -836,17 +840,15 @@ void GstEnginePipeline::TransitionToNext() {
}
qint64 GstEnginePipeline::position() const {
GstFormat fmt = GST_FORMAT_TIME;
gint64 value = 0;
gst_element_query_position(pipeline_, &fmt, &value);
gst_element_query_position(pipeline_, GST_FORMAT_TIME, &value);
return value;
}
qint64 GstEnginePipeline::length() const {
GstFormat fmt = GST_FORMAT_TIME;
gint64 value = 0;
gst_element_query_duration(pipeline_, &fmt, &value);
gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &value);
return value;
}
@ -906,7 +908,8 @@ void GstEnginePipeline::UpdateEqualizer() {
else
gain *= 0.12;
GstObject* band = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), i);
GstObject* band = GST_OBJECT(
gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(equalizer_), i));
g_object_set(G_OBJECT(band), "gain", gain, NULL);
g_object_unref(G_OBJECT(band));
}

View File

@ -126,8 +126,8 @@ class GstEnginePipeline : public QObject {
static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage*, gpointer);
static gboolean BusCallback(GstBus*, GstMessage*, gpointer);
static void NewPadCallback(GstElement*, GstPad*, gpointer);
static bool HandoffCallback(GstPad*, GstBuffer*, gpointer);
static bool EventHandoffCallback(GstPad*, GstEvent*, gpointer);
static GstPadProbeReturn HandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static GstPadProbeReturn EventHandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
static void SourceDrainedCallback(GstURIDecodeBin*, gpointer);
static void SourceSetupCallback(GstURIDecodeBin*, GParamSpec *pspec, gpointer);
static void TaskEnterCallback(GstTask*, GThread*, gpointer);

View File

@ -108,12 +108,13 @@ void MoodbarPipeline::Start() {
// Connect signals
CHECKED_GCONNECT(decodebin, "pad-added", &NewPadCallback, this);
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this, NULL);
// Set appsink callbacks
GstAppSinkCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.new_buffer = NewBufferCallback;
callbacks.new_sample = NewBufferCallback;
gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(appsink), &callbacks, this, NULL);
@ -151,8 +152,12 @@ void MoodbarPipeline::NewPadCallback(GstElement*, GstPad* pad, gpointer data) {
GstFlowReturn MoodbarPipeline::NewBufferCallback(GstAppSink* app_sink, gpointer data) {
MoodbarPipeline* self = reinterpret_cast<MoodbarPipeline*>(data);
GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink);
self->data_.append(reinterpret_cast<const char*>(buffer->data), buffer->size);
GstSample* sample = gst_app_sink_pull_sample(app_sink);
GstBuffer* buffer = gst_sample_get_buffer(sample);
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_READ);
self->data_.append(reinterpret_cast<const char*>(map.data), map.size);
gst_buffer_unmap(buffer, &map);
gst_buffer_unref(buffer);
return GST_FLOW_OK;
@ -187,7 +192,8 @@ void MoodbarPipeline::Cleanup() {
Q_ASSERT(QThread::currentThread() != qApp->thread());
if (pipeline_) {
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL, NULL);
gst_element_set_state(pipeline_, GST_STATE_NULL);
gst_object_unref(pipeline_);
pipeline_ = NULL;

View File

@ -70,7 +70,7 @@ QString Chromaprinter::CreateFingerprint() {
pipeline_ = gst_pipeline_new("pipeline");
GstElement* src = CreateElement("filesrc", pipeline_);
GstElement* decode = CreateElement("decodebin2", pipeline_);
GstElement* decode = CreateElement("decodebin", pipeline_);
GstElement* convert = CreateElement("audioconvert", pipeline_);
GstElement* resample = CreateElement("audioresample", pipeline_);
GstElement* sink = CreateElement("appsink", pipeline_);
@ -85,10 +85,10 @@ QString Chromaprinter::CreateFingerprint() {
gst_element_link_many(src, decode, NULL);
gst_element_link_many(convert, resample, NULL);
// Chromaprint expects mono floats at a sample rate of 11025Hz.
// Chromaprint expects mono 16-bit ints at a sample rate of 11025Hz.
GstCaps* caps = gst_caps_new_simple(
"audio/x-raw-int",
"width", G_TYPE_INT, 16,
"audio/x-raw",
"format", G_TYPE_STRING, "S16LE",
"channels", G_TYPE_INT, kDecodeChannels,
"rate", G_TYPE_INT, kDecodeRate,
NULL);
@ -97,7 +97,7 @@ QString Chromaprinter::CreateFingerprint() {
GstAppSinkCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.new_buffer = NewBufferCallback;
callbacks.new_sample = NewBufferCallback;
gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks, this, NULL);
g_object_set(G_OBJECT(sink), "sync", FALSE, NULL);
g_object_set(G_OBJECT(sink), "emit-signals", TRUE, NULL);
@ -106,8 +106,9 @@ QString Chromaprinter::CreateFingerprint() {
g_object_set(src, "location", filename_.toUtf8().constData(), NULL);
// Connect signals
CHECKED_GCONNECT(decode, "new-decoded-pad", &NewPadCallback, this);
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this);
CHECKED_GCONNECT(decode, "pad-added", &NewPadCallback, this);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this, NULL);
guint bus_callback_id = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);
QTime time;
@ -151,9 +152,10 @@ QString Chromaprinter::CreateFingerprint() {
qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time;
// Cleanup
callbacks.new_buffer = NULL;
callbacks.new_sample = NULL;
gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks, this, NULL);
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL);
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL, NULL);
g_source_remove(bus_callback_id);
gst_element_set_state(pipeline_, GST_STATE_NULL);
gst_object_unref(pipeline_);
@ -161,7 +163,7 @@ QString Chromaprinter::CreateFingerprint() {
return fingerprint;
}
void Chromaprinter::NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data) {
void Chromaprinter::NewPadCallback(GstElement*, GstPad* pad, gpointer data) {
Chromaprinter* instance = reinterpret_cast<Chromaprinter*>(data);
GstPad* const audiopad = gst_element_get_static_pad(
instance->convert_element_, "sink");
@ -228,13 +230,16 @@ GstFlowReturn Chromaprinter::NewBufferCallback(GstAppSink* app_sink, gpointer se
return GST_FLOW_OK;
}
GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink);
me->buffer_.write(reinterpret_cast<const char*>(buffer->data), buffer->size);
GstSample* sample = gst_app_sink_pull_sample(app_sink);
GstBuffer* buffer = gst_sample_get_buffer(sample);
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_READ);
me->buffer_.write(reinterpret_cast<const char*>(map.data), map.size);
gst_buffer_unmap(buffer, &map);
gst_buffer_unref(buffer);
gint64 pos = 0;
GstFormat format = GST_FORMAT_TIME;
gboolean ret = gst_element_query_position(me->pipeline_, &format, &pos);
gboolean ret = gst_element_query_position(me->pipeline_, GST_FORMAT_TIME, &pos);
if (ret && pos > 30 * kNsecPerSec) {
me->finishing_ = true;
g_main_loop_quit(me->event_loop_);

View File

@ -49,7 +49,7 @@ private:
void ReportError(GstMessage* message);
static void NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data);
static void NewPadCallback(GstElement*, GstPad* pad, gpointer data);
static gboolean BusCallback(GstBus*, GstMessage* msg, gpointer data);
static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage* msg, gpointer data);
static GstFlowReturn NewBufferCallback(GstAppSink* app_sink, gpointer self);

View File

@ -100,7 +100,7 @@ GstElement* Transcoder::CreateElementForMimeType(const QString& element_type,
// The caps we're trying to find
GstCaps* target_caps = gst_caps_from_string(mime_type.toUtf8().constData());
GstRegistry* registry = gst_registry_get_default();
GstRegistry* registry = gst_registry_get();
GList* const features =
gst_registry_get_feature_list(registry, GST_TYPE_ELEMENT_FACTORY);
@ -108,7 +108,7 @@ GstElement* Transcoder::CreateElementForMimeType(const QString& element_type,
GstElementFactory* factory = GST_ELEMENT_FACTORY(p->data);
// Is this the right type of plugin?
if (QString(factory->details.klass).contains(element_type)) {
if (QString(gst_element_factory_get_klass(factory)).contains(element_type)) {
const GList* const templates =
gst_element_factory_get_static_pad_templates(factory);
for (const GList* p = templates ; p ; p = g_list_next(p)) {
@ -124,7 +124,7 @@ GstElement* Transcoder::CreateElementForMimeType(const QString& element_type,
if (intersection) {
if (!gst_caps_is_empty(intersection)) {
int rank = gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(factory));
QString name = GST_PLUGIN_FEATURE_NAME(factory);
QString name = GST_OBJECT_NAME(factory);
if (name.startsWith("ffmux") || name.startsWith("ffenc"))
rank = -1; // ffmpeg usually sucks
@ -451,7 +451,8 @@ bool Transcoder::StartJob(const Job &job) {
state->convert_element_ = convert;
CHECKED_GCONNECT(decode, "new-decoded-pad", &NewPadCallback, state.get());
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(state->pipeline_)), BusCallbackSync, state.get());
gst_bus_set_sync_handler(
gst_pipeline_get_bus(GST_PIPELINE(state->pipeline_)), BusCallbackSync, state.get(), NULL);
state->bus_callback_id_ = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(state->pipeline_)), BusCallback, state.get());
// Start the pipeline
@ -494,7 +495,7 @@ bool Transcoder::event(QEvent* e) {
// Remove event handlers from the gstreamer pipeline so they don't get
// called after the pipeline is shutting down
gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(
finished_event->state_->pipeline_)), NULL, NULL);
finished_event->state_->pipeline_)), NULL, NULL, NULL);
g_source_remove(finished_event->state_->bus_callback_id_);
// Remove it from the list - this will also destroy the GStreamer pipeline
@ -524,7 +525,7 @@ void Transcoder::Cancel() {
// Remove event handlers from the gstreamer pipeline so they don't get
// called after the pipeline is shutting down
gst_bus_set_sync_handler(gst_pipeline_get_bus(
GST_PIPELINE(state->pipeline_)), NULL, NULL);
GST_PIPELINE(state->pipeline_)), NULL, NULL, NULL);
g_source_remove(state->bus_callback_id_);
// Stop the pipeline
@ -547,10 +548,9 @@ QMap<QString, float> Transcoder::GetProgress() const {
gint64 position = 0;
gint64 duration = 0;
GstFormat format = GST_FORMAT_TIME;
gst_element_query_position(state->pipeline_, &format, &position);
gst_element_query_duration(state->pipeline_, &format, &duration);
gst_element_query_position(state->pipeline_, GST_FORMAT_TIME, &position);
gst_element_query_duration(state->pipeline_, GST_FORMAT_TIME, &duration);
ret[state->job_.input] = float(position) / duration;
}

View File

@ -140,7 +140,9 @@
#include <cmath>
#ifdef HAVE_AUDIOCD
#include <gst/cdda/gstcddabasesrc.h>
#endif
using boost::shared_ptr;
using boost::scoped_ptr;

View File

@ -162,11 +162,15 @@ void ProjectMVisualisation::SetDuration(int seconds) {
}
void ProjectMVisualisation::ConsumeBuffer(GstBuffer* buffer, int) {
const int samples_per_channel = GST_BUFFER_SIZE(buffer) / sizeof(short) / 2;
const short* data = reinterpret_cast<short*>(GST_BUFFER_DATA(buffer));
GstMapInfo map;
gst_buffer_map(buffer, &map, GST_MAP_READ);
const int samples_per_channel = map.size / sizeof(short) / 2;
const short* data = reinterpret_cast<short*>(map.data);
if (projectm_)
projectm_->pcm()->addPCM16Data(data, samples_per_channel);
gst_buffer_unmap(buffer, &map);
gst_buffer_unref(buffer);
}