From 81b3c01d0417bf4b7888bab67fb9912ce48e773d Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Wed, 27 May 2009 00:16:30 +0100 Subject: [PATCH] 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. --- gst/dvdlpcmdec/Makefile.am | 4 +- gst/dvdlpcmdec/gstdvdlpcmdec.c | 169 ++++++++++++++++++++++++--------- 2 files changed, 126 insertions(+), 47 deletions(-) diff --git a/gst/dvdlpcmdec/Makefile.am b/gst/dvdlpcmdec/Makefile.am index 7ecdb2578b..7fe692e285 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 9b9e5c5f40..b23d254e6f 100644 --- a/gst/dvdlpcmdec/gstdvdlpcmdec.c +++ b/gst/dvdlpcmdec/gstdvdlpcmdec.c @@ -26,6 +26,7 @@ #include #include "gstdvdlpcmdec.h" +#include 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),