diff --git a/gst/inter/gstinteraudiosink.c b/gst/inter/gstinteraudiosink.c index 6e338affee..d9cca724ea 100644 --- a/gst/inter/gstinteraudiosink.c +++ b/gst/inter/gstinteraudiosink.c @@ -61,6 +61,8 @@ static void gst_inter_audio_sink_get_times (GstBaseSink * sink, GstBuffer * buffer, GstClockTime * start, GstClockTime * end); static gboolean gst_inter_audio_sink_start (GstBaseSink * sink); static gboolean gst_inter_audio_sink_stop (GstBaseSink * sink); +static gboolean gst_inter_audio_sink_set_caps (GstBaseSink * sink, + GstCaps * caps); static GstFlowReturn gst_inter_audio_sink_render (GstBaseSink * sink, GstBuffer * buffer); @@ -108,6 +110,7 @@ gst_inter_audio_sink_class_init (GstInterAudioSinkClass * klass) GST_DEBUG_FUNCPTR (gst_inter_audio_sink_get_times); base_sink_class->start = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_start); base_sink_class->stop = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_stop); + base_sink_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_set_caps); base_sink_class->render = GST_DEBUG_FUNCPTR (gst_inter_audio_sink_render); g_object_class_install_property (gobject_class, PROP_CHANNEL, @@ -177,10 +180,10 @@ gst_inter_audio_sink_get_times (GstBaseSink * sink, GstBuffer * buffer, if (GST_BUFFER_DURATION_IS_VALID (buffer)) { *end = *start + GST_BUFFER_DURATION (buffer); } else { - if (interaudiosink->fps_n > 0) { + if (interaudiosink->info.rate > 0) { *end = *start + - gst_util_uint64_scale_int (GST_SECOND, interaudiosink->fps_d, - interaudiosink->fps_n); + gst_util_uint64_scale_int (gst_buffer_get_size (buffer), GST_SECOND, + interaudiosink->info.rate * interaudiosink->info.bpf); } } } @@ -194,6 +197,9 @@ gst_inter_audio_sink_start (GstBaseSink * sink) GST_DEBUG ("start"); interaudiosink->surface = gst_inter_surface_get (interaudiosink->channel); + g_mutex_lock (&interaudiosink->surface->mutex); + memset (&interaudiosink->surface->audio_info, 0, sizeof (GstAudioInfo)); + g_mutex_unlock (&interaudiosink->surface->mutex); return TRUE; } @@ -207,6 +213,7 @@ gst_inter_audio_sink_stop (GstBaseSink * sink) g_mutex_lock (&interaudiosink->surface->mutex); gst_adapter_clear (interaudiosink->surface->audio_adapter); + memset (&interaudiosink->surface->audio_info, 0, sizeof (GstAudioInfo)); g_mutex_unlock (&interaudiosink->surface->mutex); gst_inter_surface_unref (interaudiosink->surface); @@ -215,22 +222,41 @@ gst_inter_audio_sink_stop (GstBaseSink * sink) return TRUE; } +static gboolean +gst_inter_audio_sink_set_caps (GstBaseSink * sink, GstCaps * caps) +{ + GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink); + GstAudioInfo info; + + if (!gst_audio_info_from_caps (&info, caps)) { + GST_ERROR_OBJECT (sink, "Failed to parse caps %" GST_PTR_FORMAT, caps); + return FALSE; + } + + g_mutex_lock (&interaudiosink->surface->mutex); + interaudiosink->surface->audio_info = info; + interaudiosink->info = info; + g_mutex_unlock (&interaudiosink->surface->mutex); + + return TRUE; +} + static GstFlowReturn gst_inter_audio_sink_render (GstBaseSink * sink, GstBuffer * buffer) { GstInterAudioSink *interaudiosink = GST_INTER_AUDIO_SINK (sink); - int n; + int n, bpf; GST_DEBUG ("render %" G_GSIZE_FORMAT, gst_buffer_get_size (buffer)); + bpf = interaudiosink->info.bpf; g_mutex_lock (&interaudiosink->surface->mutex); n = gst_adapter_available (interaudiosink->surface->audio_adapter) / 4; #define SIZE 1600 - if (n > (SIZE * 3)) { - int n_chunks = (n / (SIZE / 2)) - 4; - GST_WARNING ("flushing %d samples", n_chunks * 800); + if (n > SIZE * 3) { + GST_WARNING ("flushing %d samples", SIZE / 2); gst_adapter_flush (interaudiosink->surface->audio_adapter, - n_chunks * (SIZE / 2) * 4); + (SIZE / 2) * bpf); } gst_adapter_push (interaudiosink->surface->audio_adapter, gst_buffer_ref (buffer)); diff --git a/gst/inter/gstinteraudiosink.h b/gst/inter/gstinteraudiosink.h index a85d66aa8d..fc184a77d9 100644 --- a/gst/inter/gstinteraudiosink.h +++ b/gst/inter/gstinteraudiosink.h @@ -41,8 +41,7 @@ struct _GstInterAudioSink GstInterSurface *surface; char *channel; - int fps_n; - int fps_d; + GstAudioInfo info; }; struct _GstInterAudioSinkClass diff --git a/gst/inter/gstinteraudiosrc.c b/gst/inter/gstinteraudiosrc.c index 16d40103ed..ccb8ec2488 100644 --- a/gst/inter/gstinteraudiosrc.c +++ b/gst/inter/gstinteraudiosrc.c @@ -57,6 +57,8 @@ static void gst_inter_audio_src_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec); static void gst_inter_audio_src_finalize (GObject * object); +static GstCaps *gst_inter_audio_src_get_caps (GstBaseSrc * src, + GstCaps * filter); static gboolean gst_inter_audio_src_set_caps (GstBaseSrc * src, GstCaps * caps); static gboolean gst_inter_audio_src_start (GstBaseSrc * src); static gboolean gst_inter_audio_src_stop (GstBaseSrc * src); @@ -86,6 +88,7 @@ GST_STATIC_PAD_TEMPLATE ("src", /* class initialization */ +#define parent_class gst_inter_audio_src_parent_class G_DEFINE_TYPE (GstInterAudioSrc, gst_inter_audio_src, GST_TYPE_BASE_SRC); static void @@ -110,6 +113,7 @@ gst_inter_audio_src_class_init (GstInterAudioSrcClass * klass) gobject_class->set_property = gst_inter_audio_src_set_property; gobject_class->get_property = gst_inter_audio_src_get_property; gobject_class->finalize = gst_inter_audio_src_finalize; + base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_src_get_caps); base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_inter_audio_src_set_caps); base_src_class->start = GST_DEBUG_FUNCPTR (gst_inter_audio_src_start); base_src_class->stop = GST_DEBUG_FUNCPTR (gst_inter_audio_src_stop); @@ -178,36 +182,51 @@ gst_inter_audio_src_finalize (GObject * object) G_OBJECT_CLASS (gst_inter_audio_src_parent_class)->finalize (object); } +static GstCaps * +gst_inter_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter) +{ + GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src); + GstCaps *caps; + + GST_DEBUG_OBJECT (interaudiosrc, "get_caps"); + + if (!interaudiosrc->surface) + return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter); + + g_mutex_lock (&interaudiosrc->surface->mutex); + if (interaudiosrc->surface->audio_info.finfo) { + caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info); + if (filter) { + GstCaps *tmp; + + tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = tmp; + } + } else { + caps = NULL; + } + g_mutex_unlock (&interaudiosrc->surface->mutex); + + if (caps) + return caps; + else + return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter); +} + static gboolean gst_inter_audio_src_set_caps (GstBaseSrc * src, GstCaps * caps) { GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src); - const GstStructure *structure; - GstAudioInfo info; - gboolean ret; - int sample_rate; GST_DEBUG_OBJECT (interaudiosrc, "set_caps"); - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "rate", &sample_rate)) { - GST_ERROR_OBJECT (src, "Audio caps without rate"); + if (!gst_audio_info_from_caps (&interaudiosrc->info, caps)) { + GST_ERROR_OBJECT (src, "Failed to parse caps %" GST_PTR_FORMAT, caps); return FALSE; } - interaudiosrc->sample_rate = sample_rate; - - if (!gst_audio_info_from_caps (&info, caps)) { - GST_ERROR_OBJECT (src, "Can't parse audio caps"); - return FALSE; - } - - interaudiosrc->finfo = info.finfo; - - ret = gst_pad_set_caps (src->srcpad, caps); - - return ret; + return gst_pad_set_caps (src->srcpad, caps); } static gboolean @@ -218,6 +237,8 @@ gst_inter_audio_src_start (GstBaseSrc * src) GST_DEBUG_OBJECT (interaudiosrc, "start"); interaudiosrc->surface = gst_inter_surface_get (interaudiosrc->channel); + interaudiosrc->timestamp_offset = 0; + interaudiosrc->n_samples = 0; return TRUE; } @@ -231,7 +252,6 @@ gst_inter_audio_src_stop (GstBaseSrc * src) gst_inter_surface_unref (interaudiosrc->surface); interaudiosrc->surface = NULL; - interaudiosrc->finfo = NULL; return TRUE; } @@ -268,38 +288,68 @@ gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size, GstBuffer ** buf) { GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src); + GstCaps *caps; GstBuffer *buffer; - int n; + int n, bpf; GST_DEBUG_OBJECT (interaudiosrc, "create"); buffer = NULL; + caps = NULL; g_mutex_lock (&interaudiosrc->surface->mutex); - n = gst_adapter_available (interaudiosrc->surface->audio_adapter) / 4; + if (interaudiosrc->surface->audio_info.finfo) { + if (!gst_audio_info_is_equal (&interaudiosrc->surface->audio_info, + &interaudiosrc->info)) { + caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info); + interaudiosrc->timestamp_offset = + gst_util_uint64_scale_int (interaudiosrc->n_samples, GST_SECOND, + interaudiosrc->info.rate); + interaudiosrc->n_samples = 0; + } + } + + bpf = interaudiosrc->surface->audio_info.bpf; + + n = bpf > + 0 ? gst_adapter_available (interaudiosrc->surface->audio_adapter) / + bpf : 0; if (n > SIZE * 3) { GST_WARNING ("flushing %d samples", SIZE / 2); - gst_adapter_flush (interaudiosrc->surface->audio_adapter, (SIZE / 2) * 4); + gst_adapter_flush (interaudiosrc->surface->audio_adapter, (SIZE / 2) * bpf); n -= (SIZE / 2); } if (n > SIZE) n = SIZE; if (n > 0) { buffer = gst_adapter_take_buffer (interaudiosrc->surface->audio_adapter, - n * 4); + n * bpf); } else { buffer = gst_buffer_new (); } g_mutex_unlock (&interaudiosrc->surface->mutex); + if (caps) { + gboolean ret = gst_base_src_set_caps (src, caps); + gst_caps_unref (caps); + if (!ret) { + GST_ERROR_OBJECT (src, "Failed to set caps %" GST_PTR_FORMAT, caps); + if (buffer) + gst_buffer_unref (buffer); + return GST_FLOW_NOT_NEGOTIATED; + } + } + + bpf = interaudiosrc->info.bpf; if (n < SIZE) { GstMapInfo map; GstMemory *mem; GST_WARNING ("creating %d samples of silence", SIZE - n); - mem = gst_allocator_alloc (NULL, (SIZE - n) * 4, NULL); + mem = gst_allocator_alloc (NULL, (SIZE - n) * bpf, NULL); if (gst_memory_map (mem, &map, GST_MAP_WRITE)) { - gst_audio_format_fill_silence (interaudiosrc->finfo, map.data, map.size); + gst_audio_format_fill_silence (interaudiosrc->info.finfo, map.data, + map.size); gst_memory_unmap (mem, &map); } buffer = gst_buffer_make_writable (buffer); @@ -311,12 +361,12 @@ gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size, GST_BUFFER_OFFSET_END (buffer) = interaudiosrc->n_samples + n; GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale_int (interaudiosrc->n_samples, GST_SECOND, - interaudiosrc->sample_rate); + interaudiosrc->info.rate); GST_DEBUG_OBJECT (interaudiosrc, "create ts %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (interaudiosrc->n_samples + n, GST_SECOND, - interaudiosrc->sample_rate) - GST_BUFFER_TIMESTAMP (buffer); + interaudiosrc->info.rate) - GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_OFFSET (buffer) = interaudiosrc->n_samples; GST_BUFFER_OFFSET_END (buffer) = -1; GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); @@ -333,6 +383,7 @@ gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size, static gboolean gst_inter_audio_src_query (GstBaseSrc * src, GstQuery * query) { + GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src); gboolean ret; GST_DEBUG_OBJECT (src, "query"); @@ -341,18 +392,26 @@ gst_inter_audio_src_query (GstBaseSrc * src, GstQuery * query) case GST_QUERY_LATENCY:{ GstClockTime min_latency, max_latency; - min_latency = 30 * gst_util_uint64_scale_int (GST_SECOND, SIZE, 48000); + if (interaudiosrc->info.rate > 0) { + /* FIXME: Where does the 30 come from? */ - max_latency = min_latency; + min_latency = + 30 * gst_util_uint64_scale_int (GST_SECOND, SIZE, + interaudiosrc->info.rate); - GST_ERROR_OBJECT (src, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); + max_latency = min_latency; - gst_query_set_latency (query, - gst_base_src_is_live (src), min_latency, max_latency); + GST_ERROR_OBJECT (src, + "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - ret = TRUE; + gst_query_set_latency (query, + gst_base_src_is_live (src), min_latency, max_latency); + + ret = TRUE; + } else { + ret = FALSE; + } break; } default: @@ -375,6 +434,7 @@ gst_inter_audio_src_fixate (GstBaseSrc * src, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); + gst_structure_fixate_field_string (structure, "format", GST_AUDIO_NE (S16)); gst_structure_fixate_field_nearest_int (structure, "channels", 2); gst_structure_fixate_field_nearest_int (structure, "rate", 48000); diff --git a/gst/inter/gstinteraudiosrc.h b/gst/inter/gstinteraudiosrc.h index 318bb39dec..93d26ac11b 100644 --- a/gst/inter/gstinteraudiosrc.h +++ b/gst/inter/gstinteraudiosrc.h @@ -43,9 +43,8 @@ struct _GstInterAudioSrc char *channel; guint64 n_samples; - int sample_rate; - - const GstAudioFormatInfo *finfo; + GstClockTime timestamp_offset; + GstAudioInfo info; }; struct _GstInterAudioSrcClass diff --git a/gst/inter/gstintersurface.h b/gst/inter/gstintersurface.h index 10754af5c1..8776633eb3 100644 --- a/gst/inter/gstintersurface.h +++ b/gst/inter/gstintersurface.h @@ -21,6 +21,7 @@ #define _GST_INTER_SURFACE_H_ #include +#include #include G_BEGIN_DECLS @@ -39,8 +40,7 @@ struct _GstInterSurface int video_buffer_count; /* audio */ - int sample_rate; - int n_channels; + GstAudioInfo audio_info; GstBuffer *video_buffer; GstBuffer *sub_buffer;