mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
directsoundsink: add support for ac-3 over spdif
This commit is contained in:
parent
94e54887fb
commit
7d64e16b30
1 changed files with 150 additions and 11 deletions
|
@ -55,6 +55,7 @@
|
|||
#include <gst/base/gstbasesink.h>
|
||||
#include <gst/audio/streamvolume.h>
|
||||
#include "gstdirectsoundsink.h"
|
||||
#include <gst/audio/gstaudioiec61937.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
@ -79,6 +80,8 @@ static void gst_directsound_sink_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink,
|
||||
GstCaps * filter);
|
||||
static GstBuffer *gst_directsound_sink_payload (GstAudioBaseSink * sink,
|
||||
GstBuffer * buf);
|
||||
static gboolean gst_directsound_sink_prepare (GstAudioSink * asink,
|
||||
GstAudioRingBufferSpec * spec);
|
||||
static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink);
|
||||
|
@ -90,6 +93,7 @@ static guint gst_directsound_sink_delay (GstAudioSink * asink);
|
|||
static void gst_directsound_sink_reset (GstAudioSink * asink);
|
||||
static GstCaps *gst_directsound_probe_supported_formats (GstDirectSoundSink *
|
||||
dsoundsink, const GstCaps * template_caps);
|
||||
static gboolean gst_directsound_sink_query (GstBaseSink * pad, GstQuery * query);
|
||||
|
||||
static void gst_directsound_sink_set_volume (GstDirectSoundSink * sink,
|
||||
gdouble volume, gboolean store);
|
||||
|
@ -110,7 +114,7 @@ static GstStaticPadTemplate directsoundsink_sink_factory =
|
|||
"format = (string) S8, "
|
||||
"layout = (string) interleaved, "
|
||||
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];"
|
||||
"audio/x-iec958"));
|
||||
"audio/x-ac3, framed = (boolean) true;"));
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -136,6 +140,7 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
|
|||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
|
||||
GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (klass);
|
||||
GstAudioBaseSinkClass *gstaudiobasesink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0,
|
||||
|
@ -150,6 +155,12 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
|
|||
gstbasesink_class->get_caps =
|
||||
GST_DEBUG_FUNCPTR (gst_directsound_sink_getcaps);
|
||||
|
||||
gstbasesink_class->query =
|
||||
GST_DEBUG_FUNCPTR (gst_directsound_sink_query);
|
||||
|
||||
gstaudiobasesink_class->payload =
|
||||
GST_DEBUG_FUNCPTR (gst_directsound_sink_payload);
|
||||
|
||||
gstaudiosink_class->prepare =
|
||||
GST_DEBUG_FUNCPTR (gst_directsound_sink_prepare);
|
||||
gstaudiosink_class->unprepare =
|
||||
|
@ -274,6 +285,82 @@ gst_directsound_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
|
|||
return caps;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_directsound_sink_acceptcaps (GstBaseSink * sink, GstQuery * query)
|
||||
{
|
||||
GstDirectSoundSink *dsink = GST_DIRECTSOUND_SINK (sink);
|
||||
GstAudioRingBuffer *rbuf = GST_AUDIO_BASE_SINK (dsink)->ringbuffer;
|
||||
GstPad *pad;
|
||||
GstCaps *caps;
|
||||
GstCaps *pad_caps;
|
||||
GstStructure *st;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
GstAudioRingBufferSpec spec = { 0 };
|
||||
|
||||
if (G_UNLIKELY (dsink == NULL))
|
||||
return FALSE;
|
||||
|
||||
pad = sink->sinkpad;
|
||||
|
||||
gst_query_parse_accept_caps (query, &caps);
|
||||
GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
pad_caps = gst_pad_query_caps (pad, NULL);
|
||||
if (pad_caps) {
|
||||
ret = gst_caps_can_intersect (pad_caps, caps);
|
||||
gst_caps_unref (pad_caps);
|
||||
if (!ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 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:
|
||||
{
|
||||
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:
|
||||
gst_object_unref (dsink);
|
||||
gst_query_set_accept_caps_result (query, ret);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_directsound_sink_query (GstBaseSink * sink, GstQuery * query)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_ACCEPT_CAPS:
|
||||
res = gst_directsound_sink_acceptcaps (sink, query);
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_directsound_sink_open (GstAudioSink * asink)
|
||||
{
|
||||
|
@ -301,6 +388,14 @@ gst_directsound_sink_open (GstAudioSink * asink)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static boolean
|
||||
gst_directsound_sink_is_spdif_format (GstDirectSoundSink * dsoundsink)
|
||||
{
|
||||
GstAudioRingBufferFormatType type;
|
||||
type = GST_AUDIO_BASE_SINK (dsoundsink)->ringbuffer->spec.type;
|
||||
return type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_directsound_sink_prepare (GstAudioSink * asink,
|
||||
GstAudioRingBufferSpec * spec)
|
||||
|
@ -318,7 +413,7 @@ gst_directsound_sink_prepare (GstAudioSink * asink,
|
|||
|
||||
/* fill the WAVEFORMATEX structure with spec params */
|
||||
memset (&wfx, 0, sizeof (wfx));
|
||||
if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958) {
|
||||
if (gst_directsound_sink_is_spdif_format (dsoundsink)) {
|
||||
wfx.cbSize = sizeof (wfx);
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = spec->info.channels;
|
||||
|
@ -361,7 +456,7 @@ gst_directsound_sink_prepare (GstAudioSink * asink,
|
|||
dsoundsink->buffer_size = spec->segsize * spec->segtotal;
|
||||
|
||||
GST_INFO_OBJECT (dsoundsink,
|
||||
"GstRingBufferSpec->channels: %d, GstRingBufferSpec->rate: %d, GstRingBufferSpec->bytes_per_sample: %d\n"
|
||||
"GstAudioRingBufferSpec->channels: %d, GstAudioRingBufferSpec->rate: %d, GstAudioRingBufferSpec->bytes_per_sample: %d\n"
|
||||
"WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d, WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n"
|
||||
"Size of dsound circular buffer=>%d\n", spec->info.channels,
|
||||
spec->info.rate, spec->info.bpf, wfx.nSamplesPerSec, wfx.wBitsPerSample,
|
||||
|
@ -371,7 +466,7 @@ gst_directsound_sink_prepare (GstAudioSink * asink,
|
|||
memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
|
||||
descSecondary.dwSize = sizeof (DSBUFFERDESC);
|
||||
descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
|
||||
if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
|
||||
if (!gst_directsound_sink_is_spdif_format (dsoundsink))
|
||||
descSecondary.dwFlags |= DSBCAPS_CTRLVOLUME;
|
||||
|
||||
descSecondary.dwBufferBytes = dsoundsink->buffer_size;
|
||||
|
@ -436,10 +531,6 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
|
|||
|
||||
dsoundsink = GST_DIRECTSOUND_SINK (asink);
|
||||
|
||||
/* Fix endianness */
|
||||
if (dsoundsink->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
|
||||
_swab (data, data, length);
|
||||
|
||||
GST_DSOUND_LOCK (dsoundsink);
|
||||
|
||||
/* get current buffer status */
|
||||
|
@ -639,8 +730,7 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
|
|||
GST_INFO_OBJECT (dsoundsink, "AC3 passthrough not supported "
|
||||
"(IDirectSound_CreateSoundBuffer returned: %s)\n",
|
||||
DXGetErrorString9 (hRes));
|
||||
caps =
|
||||
gst_caps_subtract (caps, gst_caps_new_empty_simple ("audio/x-iec958"));
|
||||
caps = gst_caps_subtract (caps, gst_caps_new_empty_simple ("audio/x-ac3"));
|
||||
} else {
|
||||
GST_INFO_OBJECT (dsoundsink, "AC3 passthrough supported");
|
||||
hRes = IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary);
|
||||
|
@ -651,12 +741,61 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
|
|||
}
|
||||
}
|
||||
#else
|
||||
caps = gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
|
||||
caps = gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-ac3", NULL));
|
||||
#endif
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_directsound_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
|
||||
{
|
||||
switch (sink->ringbuffer->spec.type) {
|
||||
case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
|
||||
{
|
||||
gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
|
||||
GstBuffer *out;
|
||||
GstMapInfo infobuf, infoout;
|
||||
gboolean success;
|
||||
|
||||
if (framesize <= 0)
|
||||
return NULL;
|
||||
|
||||
out = gst_buffer_new_and_alloc (framesize);
|
||||
|
||||
if (!gst_buffer_map (buf, &infobuf, GST_MAP_READWRITE))
|
||||
{
|
||||
gst_buffer_unref (out);
|
||||
return NULL;
|
||||
}
|
||||
if (!gst_buffer_map (out, &infoout, GST_MAP_READWRITE))
|
||||
{
|
||||
gst_buffer_unmap (buf, &infobuf);
|
||||
gst_buffer_unref (out);
|
||||
return NULL;
|
||||
}
|
||||
success = gst_audio_iec61937_payload (infobuf.data, infobuf.size,
|
||||
infoout.data, infoout.size, &sink->ringbuffer->spec);
|
||||
if (!success) {
|
||||
gst_buffer_unmap (out, &infoout);
|
||||
gst_buffer_unmap (buf, &infobuf);
|
||||
gst_buffer_unref (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_ALL, 0, -1);
|
||||
/* Fix endianness */
|
||||
_swab ((gchar *) infoout.data, (gchar *) infoout.data, infobuf.size);
|
||||
gst_buffer_unmap (out, &infoout);
|
||||
gst_buffer_unmap (buf, &infobuf);
|
||||
return out;
|
||||
}
|
||||
|
||||
default:
|
||||
return gst_buffer_ref (buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink,
|
||||
gdouble dvolume, gboolean store)
|
||||
|
|
Loading…
Reference in a new issue