alsasink: use the iec958 payloader to support non-payloaded input streams

This commit is contained in:
Andoni Morales Alastruey 2012-04-27 10:19:15 +02:00 committed by Sebastian Dröge
parent b7b123964b
commit c6409806c1
3 changed files with 139 additions and 4 deletions

View file

@ -163,7 +163,7 @@ gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params,
s = gst_caps_get_structure (in_caps, i);
if (!gst_structure_has_name (s, "audio/x-raw")) {
GST_WARNING_OBJECT (obj, "skipping non-raw format");
GST_DEBUG_OBJECT (obj, "skipping non-raw format");
continue;
}
@ -476,7 +476,7 @@ gst_alsa_probe_supported_formats (GstObject * obj, snd_pcm_t * handle,
snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj);
if (G_LIKELY (pcm)) {
gst_caps_append (caps, gst_caps_new_empty_simple ("audio/x-iec958"));
gst_caps_append (caps, gst_caps_from_string (PASSTHROUGH_CAPS));
snd_pcm_close (pcm);
}
}

View file

@ -39,6 +39,15 @@
(SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \
SND_LIB_SUBMINOR >= (micro)))
#define PASSTHROUGH_CAPS \
"audio/x-ac3, framed = (boolean) true;" \
"audio/x-eac3, framed = (boolean) true; " \
"audio/x-dts, framed = (boolean) true, " \
"block-size = (int) { 512, 1024, 2048 }; " \
"audio/mpeg, mpegversion = (int) 1, " \
"mpegaudioversion = (int) [ 1, 2 ], parsed = (boolean) true;"
GST_DEBUG_CATEGORY_EXTERN (alsa_debug);
#define GST_CAT_DEFAULT alsa_debug

View file

@ -51,6 +51,7 @@
#include "gstalsasink.h"
#include "gstalsadeviceprobe.h"
#include <gst/audio/gstaudioiec61937.h>
#include <gst/gst-i18n-plugin.h>
#include "gst/glib-compat-private.h"
@ -81,6 +82,7 @@ static void gst_alsasink_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter);
static gboolean gst_alsasink_query (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_alsasink_open (GstAudioSink * asink);
static gboolean gst_alsasink_prepare (GstAudioSink * asink,
@ -91,6 +93,9 @@ static gint gst_alsasink_write (GstAudioSink * asink, gpointer data,
guint length);
static guint gst_alsasink_delay (GstAudioSink * asink);
static void gst_alsasink_reset (GstAudioSink * asink);
static gboolean gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps);
static GstBuffer *gst_alsasink_payload (GstAudioBaseSink * sink,
GstBuffer * buf);
static gint output_ref; /* 0 */
static snd_output_t *output; /* NULL */
@ -104,7 +109,7 @@ static GstStaticPadTemplate alsasink_sink_factory =
"format = (string) " GST_AUDIO_FORMATS_ALL ", "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
"audio/x-iec958")
PASSTHROUGH_CAPS)
);
static void
@ -140,11 +145,13 @@ gst_alsasink_class_init (GstAlsaSinkClass * klass)
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstAudioBaseSinkClass *gstbaseaudiosink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstbaseaudiosink_class = (GstAudioBaseSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
parent_class = g_type_class_peek_parent (klass);
@ -161,6 +168,9 @@ gst_alsasink_class_init (GstAlsaSinkClass * klass)
gst_static_pad_template_get (&alsasink_sink_factory));
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_alsasink_query);
gstbaseaudiosink_class->payload = GST_DEBUG_FUNCPTR (gst_alsasink_payload);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare);
@ -312,6 +322,82 @@ gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter)
}
}
static gboolean
gst_alsasink_acceptcaps (GstAlsaSink * alsa, GstCaps * caps)
{
GstAudioRingBuffer *rbuf = GST_AUDIO_BASE_SINK (alsa)->ringbuffer;
GstPad *pad = GST_BASE_SINK (alsa)->sinkpad;
GstCaps *pad_caps;
GstStructure *st;
gboolean ret = FALSE;
GstAudioRingBufferSpec spec = { 0 };
pad_caps = gst_pad_query_caps (pad, caps);
if (!pad_caps || gst_caps_is_empty (pad_caps)) {
if (pad_caps)
gst_caps_unref (pad_caps);
ret = FALSE;
goto done;
}
gst_caps_unref (pad_caps);
/* If we've not got fixed caps, creating a stream might fail, so let's just
* return from here with default acceptcaps behaviour */
if (!gst_caps_is_fixed (caps))
goto done;
if (!gst_audio_ring_buffer_parse_caps (&rbuf->spec, caps))
goto done;
/* Make sure input is framed (one frame per buffer) and can be payloaded */
switch (rbuf->spec.type) {
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
{
gboolean framed = FALSE, parsed = FALSE;
st = gst_caps_get_structure (caps, 0);
gst_structure_get_boolean (st, "framed", &framed);
gst_structure_get_boolean (st, "parsed", &parsed);
if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
goto done;
}
default:{
}
}
ret = TRUE;
done:
return ret;
}
static gboolean
gst_alsasink_query (GstBaseSink * sink, GstQuery * query)
{
GstAlsaSink *alsa = GST_ALSA_SINK (sink);
gboolean ret;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_ACCEPT_CAPS:
{
GstCaps *caps;
gst_query_parse_accept_caps (query, &caps);
ret = gst_alsasink_acceptcaps (alsa, caps);
gst_query_set_accept_caps_result (query, ret);
ret = TRUE;
break;
}
default:
ret = GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
break;
}
return ret;
}
static int
set_hwparams (GstAlsaSink * alsa)
{
@ -693,7 +779,10 @@ alsasink_parse_spec (GstAlsaSink * alsa, GstAudioRingBufferSpec * spec)
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW:
alsa->format = SND_PCM_FORMAT_MU_LAW;
break;
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
alsa->format = SND_PCM_FORMAT_S16_BE;
alsa->iec958 = TRUE;
break;
@ -1001,3 +1090,40 @@ prepare_error:
return;
}
}
static GstBuffer *
gst_alsasink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
{
GstAlsaSink *alsa;
alsa = GST_ALSA_SINK (sink);
if (alsa->iec958) {
GstBuffer *out;
gint framesize;
GstMapInfo iinfo, oinfo;
framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
if (framesize <= 0)
return NULL;
out = gst_buffer_new_and_alloc (framesize);
gst_buffer_map (buf, &iinfo, GST_MAP_READ);
gst_buffer_map (out, &oinfo, GST_MAP_WRITE);
if (!gst_audio_iec61937_payload (iinfo.data, iinfo.size,
oinfo.data, oinfo.size, &sink->ringbuffer->spec)) {
gst_buffer_unref (out);
return NULL;
}
gst_buffer_unmap (buf, &iinfo);
gst_buffer_unmap (out, &oinfo);
gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1);
return out;
}
return gst_buffer_ref (buf);
}