diff --git a/ChangeLog b/ChangeLog index 9439e35513..fc26d8f74e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-10-10 Wim Taymans + + * gst/audiotestsrc/gstaudiotestsrc.c: + (gst_audio_test_src_class_init), (gst_audio_test_src_init), + (gst_audio_test_src_src_fixate), (gst_audio_test_src_setcaps), + (gst_audio_test_src_start), (gst_audio_test_src_stop), + (gst_audio_test_src_do_seek), (gst_audio_test_src_check_get_range), + (gst_audio_test_src_create): + * gst/audiotestsrc/gstaudiotestsrc.h: + Define the default property values in the usual place. + Implement start/stop to reset values correctly. + Calculate the sample size only once when we negotiate. + Rename some values to make more sense. + Keep track of our byte range. + Add support for pull based scheduling. Disabled for now until we have + the whole stack working. + Set the BUFFER_OFFSET correctly. + 2008-10-10 Sebastian Dröge Based on a patch by: xavierb at gmail dot com diff --git a/gst/audiotestsrc/gstaudiotestsrc.c b/gst/audiotestsrc/gstaudiotestsrc.c index 4a8c026459..f6f5a121a8 100644 --- a/gst/audiotestsrc/gstaudiotestsrc.c +++ b/gst/audiotestsrc/gstaudiotestsrc.c @@ -67,6 +67,13 @@ GST_ELEMENT_DETAILS ("Audio test source", "Creates audio test signals of given frequency and volume", "Stefan Kost "); +#define DEFAULT_SAMPLES_PER_BUFFER 1024 +#define DEFAULT_WAVE GST_AUDIO_TEST_SRC_WAVE_SINE +#define DEFAULT_FREQ 440.0 +#define DEFAULT_VOLUME 0.8 +#define DEFAULT_IS_LIVE FALSE +#define DEFAULT_TIMESTAMP_OFFSET G_GINT64_CONSTANT (0) +#define DEFAULT_CAN_ACTIVATE_PULL FALSE enum { @@ -77,6 +84,7 @@ enum PROP_VOLUME, PROP_IS_LIVE, PROP_TIMESTAMP_OFFSET, + PROP_LAST }; @@ -143,6 +151,7 @@ static gboolean gst_audio_test_src_setcaps (GstBaseSrc * basesrc, static void gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps); static gboolean gst_audio_test_src_is_seekable (GstBaseSrc * basesrc); +static gboolean gst_audio_test_src_check_get_range (GstBaseSrc * basesrc); static gboolean gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment); static gboolean gst_audio_test_src_query (GstBaseSrc * basesrc, @@ -152,6 +161,8 @@ static void gst_audio_test_src_change_wave (GstAudioTestSrc * src); static void gst_audio_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer, GstClockTime * start, GstClockTime * end); +static gboolean gst_audio_test_src_start (GstBaseSrc * basesrc); +static gboolean gst_audio_test_src_stop (GstBaseSrc * basesrc); static GstFlowReturn gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer); @@ -181,35 +192,42 @@ gst_audio_test_src_class_init (GstAudioTestSrcClass * klass) g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER, g_param_spec_int ("samplesperbuffer", "Samples per buffer", "Number of samples in each outgoing buffer", - 1, G_MAXINT, 1024, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_WAVE, g_param_spec_enum ("wave", "Waveform", "Oscillator waveform", GST_TYPE_AUDIO_TEST_SRC_WAVE, /* enum type */ - GST_AUDIO_TEST_SRC_WAVE_SINE, /* default value */ + 1, G_MAXINT, DEFAULT_SAMPLES_PER_BUFFER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_WAVE, + g_param_spec_enum ("wave", "Waveform", "Oscillator waveform", + GST_TYPE_AUDIO_TEST_SRC_WAVE, GST_AUDIO_TEST_SRC_WAVE_SINE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FREQ, g_param_spec_double ("freq", "Frequency", "Frequency of test signal", - 0.0, 20000.0, 440.0, + 0.0, 20000.0, DEFAULT_FREQ, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_VOLUME, g_param_spec_double ("volume", "Volume", "Volume of test signal", 0.0, - 1.0, 0.8, + 1.0, DEFAULT_VOLUME, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_IS_LIVE, g_param_spec_boolean ("is-live", "Is Live", - "Whether to act as a live source", FALSE, + "Whether to act as a live source", DEFAULT_IS_LIVE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset", "Timestamp offset", "An offset added to timestamps set on buffers (in ns)", G_MININT64, - G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_MAXINT64, DEFAULT_TIMESTAMP_OFFSET, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_test_src_setcaps); gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_audio_test_src_is_seekable); + gstbasesrc_class->check_get_range = + GST_DEBUG_FUNCPTR (gst_audio_test_src_check_get_range); gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_audio_test_src_do_seek); gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_audio_test_src_query); gstbasesrc_class->get_times = GST_DEBUG_FUNCPTR (gst_audio_test_src_get_times); + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_audio_test_src_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_audio_test_src_stop); gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_audio_test_src_create); } @@ -222,18 +240,19 @@ gst_audio_test_src_init (GstAudioTestSrc * src, GstAudioTestSrcClass * g_class) src->samplerate = 44100; src->format = GST_AUDIO_TEST_SRC_FORMAT_NONE; - src->volume = 0.8; - src->freq = 440.0; + + src->volume = DEFAULT_VOLUME; + src->freq = DEFAULT_FREQ; /* we operate in time */ gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); - gst_base_src_set_live (GST_BASE_SRC (src), FALSE); + gst_base_src_set_live (GST_BASE_SRC (src), DEFAULT_IS_LIVE); - src->samples_per_buffer = 1024; + src->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER; src->generate_samples_per_buffer = src->samples_per_buffer; - src->timestamp_offset = G_GINT64_CONSTANT (0); + src->timestamp_offset = DEFAULT_TIMESTAMP_OFFSET; - src->wave = GST_AUDIO_TEST_SRC_WAVE_SINE; + src->wave = DEFAULT_WAVE; } static void @@ -245,6 +264,8 @@ gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); + GST_DEBUG_OBJECT (src, "fixating samplerate to %d", src->samplerate); + gst_structure_fixate_field_nearest_int (structure, "rate", src->samplerate); name = gst_structure_get_name (structure); @@ -266,6 +287,8 @@ gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); ret = gst_structure_get_int (structure, "rate", &src->samplerate); + GST_DEBUG_OBJECT (src, "negotiated to samplerate %d", src->samplerate); + name = gst_structure_get_name (structure); if (strcmp (name, "audio/x-raw-int") == 0) { ret &= gst_structure_get_int (structure, "width", &width); @@ -277,6 +300,26 @@ gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps) GST_AUDIO_TEST_SRC_FORMAT_F64; } + /* allocate a new buffer suitable for this pad */ + switch (src->format) { + case GST_AUDIO_TEST_SRC_FORMAT_S16: + src->sample_size = sizeof (gint16); + break; + case GST_AUDIO_TEST_SRC_FORMAT_S32: + src->sample_size = sizeof (gint32); + break; + case GST_AUDIO_TEST_SRC_FORMAT_F32: + src->sample_size = sizeof (gfloat); + break; + case GST_AUDIO_TEST_SRC_FORMAT_F64: + src->sample_size = sizeof (gdouble); + break; + default: + /* can't really happen */ + ret = FALSE; + break; + } + gst_audio_test_src_change_wave (src); return ret; @@ -676,7 +719,7 @@ gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) if (src->accumulator >= M_PI_M2) \ src->accumulator -= M_PI_M2; \ \ - if ((src->n_samples + i)%src->samplerate < 1600) { \ + if ((src->next_sample + i)%src->samplerate < 1600) { \ samples[i] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \ } else { \ samples[i] = 0; \ @@ -784,6 +827,30 @@ gst_audio_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer, } } +static gboolean +gst_audio_test_src_start (GstBaseSrc * basesrc) +{ + GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc); + + src->next_sample = 0; + src->next_byte = 0; + src->next_time = 0; + src->check_seek_stop = FALSE; + src->eos_reached = FALSE; + src->tags_pushed = FALSE; + src->accumulator = 0; + + return TRUE; +} + +static gboolean +gst_audio_test_src_stop (GstBaseSrc * basesrc) +{ + return TRUE; +} + +/* seek to time, will be called when we operate in push mode. In pull mode we + * get the requiested byte offset. */ static gboolean gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) { @@ -794,16 +861,17 @@ gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment) time = segment->last_stop; /* now move to the time indicated */ - src->n_samples = + src->next_sample = gst_util_uint64_scale_int (time, src->samplerate, GST_SECOND); - src->running_time = - gst_util_uint64_scale_int (src->n_samples, GST_SECOND, src->samplerate); + src->next_byte = src->next_sample * src->sample_size; + src->next_time = + gst_util_uint64_scale_int (src->next_sample, GST_SECOND, src->samplerate); - g_assert (src->running_time <= time); + g_assert (src->next_time <= time); if (GST_CLOCK_TIME_IS_VALID (segment->stop)) { time = segment->stop; - src->n_samples_stop = gst_util_uint64_scale_int (time, src->samplerate, + src->sample_stop = gst_util_uint64_scale_int (time, src->samplerate, GST_SECOND); src->check_seek_stop = TRUE; } else { @@ -821,6 +889,13 @@ gst_audio_test_src_is_seekable (GstBaseSrc * basesrc) return TRUE; } +static gboolean +gst_audio_test_src_check_get_range (GstBaseSrc * basesrc) +{ + /* if we can operate in pull mode */ + return DEFAULT_CAN_ACTIVATE_PULL; +} + static GstFlowReturn gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) @@ -829,14 +904,11 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, GstAudioTestSrc *src; GstBuffer *buf; GstClockTime next_time; - gint64 n_samples; - gint sample_size; + gint64 next_sample, next_byte; + guint bytes, samples; src = GST_AUDIO_TEST_SRC (basesrc); - if (src->eos_reached) - return GST_FLOW_UNEXPECTED; - /* example for tagging generated data */ if (!src->tags_pushed) { GstTagList *taglist; @@ -852,62 +924,75 @@ gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset, src->tags_pushed = TRUE; } + if (src->eos_reached) + return GST_FLOW_UNEXPECTED; + + /* if no length was given, use our default length in samples otherwise convert + * the length in bytes to samples. */ + if (length == -1) + samples = src->samples_per_buffer; + else + samples = length / src->sample_size; + + /* if no offset was given, use our next logical byte */ + if (offset == -1) + offset = src->next_byte; + + /* now see if we are at the byteoffset we think we are */ + if (offset != src->next_byte) { + GST_DEBUG_OBJECT (src, "seek to new offset %" G_GUINT64_FORMAT, offset); + /* we have a discont in the expected sample offset, do a 'seek' */ + src->next_sample = src->next_byte / src->sample_size; + src->next_time = + gst_util_uint64_scale_int (src->next_sample, GST_SECOND, + src->samplerate); + src->next_byte = offset; + } + /* check for eos */ if (src->check_seek_stop && - (src->n_samples_stop > src->n_samples) && - (src->n_samples_stop < src->n_samples + src->samples_per_buffer) + (src->sample_stop > src->next_sample) && + (src->sample_stop < src->next_sample + samples) ) { /* calculate only partial buffer */ - src->generate_samples_per_buffer = src->n_samples_stop - src->n_samples; - n_samples = src->n_samples_stop; + src->generate_samples_per_buffer = src->sample_stop - src->next_sample; + next_sample = src->sample_stop; src->eos_reached = TRUE; } else { /* calculate full buffer */ - src->generate_samples_per_buffer = src->samples_per_buffer; - n_samples = src->n_samples + src->samples_per_buffer; - } - next_time = gst_util_uint64_scale (n_samples, GST_SECOND, - (guint64) src->samplerate); - - /* allocate a new buffer suitable for this pad */ - switch (src->format) { - case GST_AUDIO_TEST_SRC_FORMAT_S16: - sample_size = sizeof (gint16); - break; - case GST_AUDIO_TEST_SRC_FORMAT_S32: - sample_size = sizeof (gint32); - break; - case GST_AUDIO_TEST_SRC_FORMAT_F32: - sample_size = sizeof (gfloat); - break; - case GST_AUDIO_TEST_SRC_FORMAT_F64: - sample_size = sizeof (gdouble); - break; - default: - sample_size = -1; - GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), - ("format wasn't negotiated before get function")); - return GST_FLOW_NOT_NEGOTIATED; - break; + src->generate_samples_per_buffer = samples; + next_sample = src->next_sample + samples; } - if ((res = gst_pad_alloc_buffer (basesrc->srcpad, src->n_samples, - src->generate_samples_per_buffer * sample_size, - GST_PAD_CAPS (basesrc->srcpad), &buf)) != GST_FLOW_OK) { + bytes = src->generate_samples_per_buffer * src->sample_size; + + if ((res = gst_pad_alloc_buffer (basesrc->srcpad, src->next_sample, + bytes, GST_PAD_CAPS (basesrc->srcpad), &buf)) != GST_FLOW_OK) { return res; } - GST_BUFFER_TIMESTAMP (buf) = src->timestamp_offset + src->running_time; - GST_BUFFER_OFFSET_END (buf) = n_samples; - GST_BUFFER_DURATION (buf) = next_time - src->running_time; + next_byte = src->next_byte + bytes; + next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, + src->samplerate); - gst_object_sync_values (G_OBJECT (src), src->running_time); + GST_LOG_OBJECT (src, "samplerate %d", src->samplerate); + GST_LOG_OBJECT (src, "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT, + next_sample, GST_TIME_ARGS (next_time)); - src->running_time = next_time; - src->n_samples = n_samples; + GST_BUFFER_TIMESTAMP (buf) = src->timestamp_offset + src->next_time; + GST_BUFFER_OFFSET (buf) = src->next_sample; + GST_BUFFER_OFFSET_END (buf) = next_sample; + GST_BUFFER_DURATION (buf) = next_time - src->next_time; + + gst_object_sync_values (G_OBJECT (src), src->next_time); + + src->next_time = next_time; + src->next_sample = next_sample; + src->next_byte = next_byte; GST_LOG_OBJECT (src, "generating %u samples at ts %" GST_TIME_FORMAT, - length, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + src->generate_samples_per_buffer, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); src->process (src, GST_BUFFER_DATA (buf)); diff --git a/gst/audiotestsrc/gstaudiotestsrc.h b/gst/audiotestsrc/gstaudiotestsrc.h index 51d138ff57..fc8f62d343 100644 --- a/gst/audiotestsrc/gstaudiotestsrc.h +++ b/gst/audiotestsrc/gstaudiotestsrc.h @@ -107,14 +107,16 @@ struct _GstAudioTestSrc { /* audio parameters */ gint samplerate; gint samples_per_buffer; + gint sample_size; GstAudioTestSrcFormat format; /*< private >*/ gboolean tags_pushed; /* send tags just once ? */ GstClockTimeDiff timestamp_offset; /* base offset */ - GstClockTime running_time; /* total running time */ - gint64 n_samples; /* total samples sent */ - gint64 n_samples_stop; + GstClockTime next_time; /* next timestamp */ + gint64 next_sample; /* next sample to send */ + gint64 next_byte; /* next byte to send */ + gint64 sample_stop; gboolean check_seek_stop; gboolean eos_reached; gint generate_samples_per_buffer; /* used to generate a partial buffer */