summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Schmidt <thaytan@noraisin.net>2009-05-27 00:16:30 +0100
committerJan Schmidt <thaytan@noraisin.net>2009-05-27 00:31:35 +0100
commit81b3c01d0417bf4b7888bab67fb9912ce48e773d (patch)
treea45c96b8b52f2ee7c843b8c6532261a109e3ce1e
parent59f5b5f4f1bec79ebb4fa048b2310dcb837d9569 (diff)
dvdlpcmdec: Add multichannel channel maps, and send some tags
Add a multichannel map to the output caps, and send at least a CODEC and BITRATE tag. I'm not too sure about the 5.1 and 7.1 channel maps. I have no samples and can't find info about the channel ordering, but this is better than nothing.
-rw-r--r--gst/dvdlpcmdec/Makefile.am4
-rw-r--r--gst/dvdlpcmdec/gstdvdlpcmdec.c169
2 files changed, 126 insertions, 47 deletions
diff --git a/gst/dvdlpcmdec/Makefile.am b/gst/dvdlpcmdec/Makefile.am
index 7ecdb257..7fe692e2 100644
--- a/gst/dvdlpcmdec/Makefile.am
+++ b/gst/dvdlpcmdec/Makefile.am
@@ -2,8 +2,8 @@
plugin_LTLIBRARIES = libgstdvdlpcmdec.la
libgstdvdlpcmdec_la_SOURCES = gstdvdlpcmdec.c
-libgstdvdlpcmdec_la_CFLAGS = $(GST_CFLAGS)
-libgstdvdlpcmdec_la_LIBADD = $(GST_LIBS)
+libgstdvdlpcmdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdvdlpcmdec_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-@GST_MAJORMINOR@ $(GST_LIBS)
libgstdvdlpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdvdlpcmdec_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.c b/gst/dvdlpcmdec/gstdvdlpcmdec.c
index 9b9e5c5f..b23d254e 100644
--- a/gst/dvdlpcmdec/gstdvdlpcmdec.c
+++ b/gst/dvdlpcmdec/gstdvdlpcmdec.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "gstdvdlpcmdec.h"
+#include <gst/audio/multichannel.h>
GST_DEBUG_CATEGORY_STATIC (dvdlpcm_debug);
#define GST_CAT_DEFAULT dvdlpcm_debug
@@ -175,13 +176,111 @@ gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
gst_dvdlpcm_reset (dvdlpcmdec);
}
+static GstAudioChannelPosition *
+get_audio_channel_positions (GstDvdLpcmDec * dvdlpcmdec)
+{
+ gint n_channels = dvdlpcmdec->channels;
+ GstAudioChannelPosition *ret = g_new (GstAudioChannelPosition, n_channels);
+
+ /* FIXME: The channel layouts for 5.1 and 7.1 are just guesses, I can't
+ * find any samples or confirmation */
+ switch (n_channels) {
+ case 8:
+ ret[7] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
+ ret[6] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
+ /* Fall through */
+ case 6:
+ ret[5] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+ ret[4] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+ ret[3] = GST_AUDIO_CHANNEL_POSITION_LFE;
+ ret[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+ /* Fall through */
+ case 2:
+ ret[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+ ret[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+ break;
+ case 4:
+ ret[3] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
+ ret[2] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
+ ret[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
+ ret[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
+ break;
+ case 1:
+ ret[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
+ break;
+ default:
+ g_free (ret);
+ ret = NULL;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+gst_dvdlpcmdec_send_tags (GstDvdLpcmDec * dvdlpcmdec)
+{
+ GstTagList *taglist;
+ guint bitrate = dvdlpcmdec->channels * dvdlpcmdec->out_width *
+ dvdlpcmdec->rate;
+
+ taglist = gst_tag_list_new ();
+
+ gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
+ GST_TAG_AUDIO_CODEC, "LPCM Audio", GST_TAG_BITRATE, bitrate, NULL);
+
+ gst_element_found_tags_for_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->srcpad,
+ taglist);
+}
+
+static gboolean
+gst_dvdlpcmdec_set_outcaps (GstDvdLpcmDec * dvdlpcmdec)
+{
+ gboolean res = TRUE;
+ GstCaps *src_caps;
+ GstAudioChannelPosition *pos;
+
+ /* Build caps to set on the src pad, which we know from the incoming caps */
+ src_caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, dvdlpcmdec->rate,
+ "channels", G_TYPE_INT, dvdlpcmdec->channels,
+ "endianness", G_TYPE_INT, G_BIG_ENDIAN,
+ "depth", G_TYPE_INT, dvdlpcmdec->out_width,
+ "width", G_TYPE_INT, dvdlpcmdec->out_width,
+ "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ pos = get_audio_channel_positions (dvdlpcmdec);
+ if (pos) {
+ gst_audio_set_channel_positions (gst_caps_get_structure (src_caps, 0), pos);
+ g_free (pos);
+ }
+
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d (out %d)",
+ dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width,
+ dvdlpcmdec->out_width);
+
+ res = gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps);
+ if (res) {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set output caps: %"
+ GST_PTR_FORMAT, src_caps);
+
+ gst_dvdlpcmdec_send_tags (dvdlpcmdec);
+ } else {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set output caps: %"
+ GST_PTR_FORMAT, src_caps);
+ }
+
+ gst_caps_unref (src_caps);
+
+ return res;
+}
+
static gboolean
gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
{
GstStructure *structure;
gboolean res = TRUE;
GstDvdLpcmDec *dvdlpcmdec;
- GstCaps *src_caps;
g_return_val_if_fail (caps != NULL, FALSE);
g_return_val_if_fail (pad != NULL, FALSE);
@@ -190,7 +289,8 @@ gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
structure = gst_caps_get_structure (caps, 0);
- /* If we have the DVD structured LPCM (including header) */
+ /* If we have the DVD structured LPCM (including header) then we wait
+ * for incoming data before creating the output pad caps */
if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_dvd);
goto done;
@@ -216,40 +316,18 @@ gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
else
dvdlpcmdec->out_width = dvdlpcmdec->width;
- /* Build caps to set on the src pad, which we know from the incoming caps */
- src_caps = gst_caps_new_simple ("audio/x-raw-int",
- "rate", G_TYPE_INT, dvdlpcmdec->rate,
- "channels", G_TYPE_INT, dvdlpcmdec->channels,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "depth", G_TYPE_INT, dvdlpcmdec->out_width,
- "width", G_TYPE_INT, dvdlpcmdec->out_width,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
-
- GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d (out %d)",
- dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width,
- dvdlpcmdec->out_width);
-
- if (!gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps)) {
- GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set caps!");
- res = FALSE;
- } else {
- GST_DEBUG_OBJECT (dvdlpcmdec, "Successfully set caps: %" GST_PTR_FORMAT,
- caps);
- }
-
- gst_caps_unref (src_caps);
+ res = gst_dvdlpcmdec_set_outcaps (dvdlpcmdec);
done:
gst_object_unref (dvdlpcmdec);
-
return res;
/* ERRORS */
caps_parse_error:
{
GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
- res = FALSE;
- goto done;
+ gst_object_unref (dvdlpcmdec);
+ return FALSE;
}
}
@@ -382,27 +460,11 @@ gst_dvdlpcmdec_chain_dvd (GstPad * pad, GstBuffer * buf)
/* see if we have a new header */
if (header != dvdlpcmdec->header) {
- GstCaps *src_caps;
-
parse_header (dvdlpcmdec, header);
- /* Build caps to set on the src pad from what we've just parsed */
- src_caps = gst_caps_new_simple ("audio/x-raw-int",
- "rate", G_TYPE_INT, dvdlpcmdec->rate,
- "channels", G_TYPE_INT, dvdlpcmdec->channels,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "depth", G_TYPE_INT, dvdlpcmdec->out_width,
- "width", G_TYPE_INT, dvdlpcmdec->out_width,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
-
- GST_DEBUG_OBJECT (dvdlpcmdec, "Set rate %d, channels %d, width %d",
- dvdlpcmdec->rate, dvdlpcmdec->channels, dvdlpcmdec->width);
-
- if (!gst_pad_set_caps (dvdlpcmdec->srcpad, src_caps))
+ if (!gst_dvdlpcmdec_set_outcaps (dvdlpcmdec))
goto negotiation_failed;
- gst_caps_unref (src_caps);
-
dvdlpcmdec->header = header;
}
@@ -502,7 +564,8 @@ done:
/* ERRORS */
negotiation_failed:
{
- GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set caps!");
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
+ ("Failed to configure output format"));
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
@@ -540,6 +603,8 @@ gst_dvdlpcmdec_chain_raw (GstPad * pad, GstBuffer * buf)
/* We can just pass 16-bits straight through intact, once we set
* appropriate things on the buffer */
samples = size / dvdlpcmdec->channels / 2;
+ if (samples < 1)
+ goto drop;
buf = gst_buffer_make_metadata_writable (buf);
break;
}
@@ -554,6 +619,9 @@ gst_dvdlpcmdec_chain_raw (GstPad * pad, GstBuffer * buf)
GstBuffer *outbuf;
GstCaps *bufcaps = GST_PAD_CAPS (dvdlpcmdec->srcpad);
+ if (samples < 1)
+ goto drop;
+
ret = gst_pad_alloc_buffer_and_set_caps (dvdlpcmdec->srcpad, 0,
samples * 3, bufcaps, &outbuf);
@@ -602,6 +670,9 @@ gst_dvdlpcmdec_chain_raw (GstPad * pad, GstBuffer * buf)
samples = size / dvdlpcmdec->channels / 3;
+ if (samples < 1)
+ goto drop;
+
/* Ensure our output buffer is writable */
buf = gst_buffer_make_writable (buf);
@@ -640,6 +711,14 @@ done:
return ret;
/* ERRORS */
+drop:
+ {
+ GST_DEBUG_OBJECT (dvdlpcmdec, "Buffer of size %u is too small. Dropping",
+ GST_BUFFER_SIZE (buf));
+ gst_buffer_unref (buf);
+ ret = GST_FLOW_OK;
+ goto done;
+ }
not_negotiated:
{
GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),