mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
Restructure LPCM decoder to not expect the demuxer to parse the LPCM header; instead do this internally. Also support...
Original commit message from CVS: Restructure LPCM decoder to not expect the demuxer to parse the LPCM header; instead do this internally. Also support the old way, using a different mime-type. CVS:
This commit is contained in:
parent
7d7c3e478e
commit
073a2e5dc0
3 changed files with 165 additions and 27 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2005-08-31 Michael Smith <msmith@fluendo.com>
|
||||
|
||||
* gst/dvdlpcmdec/gstdvdlpcmdec.c: (gst_dvdlpcm_reset),
|
||||
(gst_dvdlpcmdec_init), (gst_dvdlpcmdec_setcaps),
|
||||
(update_timestamps), (parse_header), (gst_dvdlpcmdec_chain_dvd),
|
||||
(gst_dvdlpcmdec_chain_raw):
|
||||
* gst/dvdlpcmdec/gstdvdlpcmdec.h:
|
||||
Restructure LPCM decoder to not expect the demuxer to parse the LPCM
|
||||
header; instead do this internally. Also support the old way, using
|
||||
a different mime-type.
|
||||
|
||||
2005-08-31 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* Makefile.am:
|
||||
|
|
|
@ -35,13 +35,14 @@ static GstElementDetails gst_dvdlpcmdec_details =
|
|||
GST_ELEMENT_DETAILS ("DVD LPCM Audio decoder",
|
||||
"Codec/Demuxer/Audio",
|
||||
"Decode DVD LPCM frames into standard PCM audio",
|
||||
"Jan Schmidt <jan@noraisin.net>");
|
||||
"Jan Schmidt <jan@noraisin.net>\n" "Michael Smith <msmith@fluendo.com>");
|
||||
|
||||
static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-dvd-lpcm, "
|
||||
GST_STATIC_CAPS ("audio/x-private1-lpcm; "
|
||||
"audio/x-lpcm, "
|
||||
"width = (int) { 16, 20, 24 }, "
|
||||
"rate = (int) { 48000, 96000 }, "
|
||||
"channels = (int) [ 1, 8 ], "
|
||||
|
@ -79,8 +80,11 @@ static void gst_dvdlpcmdec_base_init (gpointer g_class);
|
|||
static void gst_dvdlpcmdec_class_init (GstDvdLpcmDecClass * klass);
|
||||
static void gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec);
|
||||
|
||||
static GstFlowReturn gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstPadLinkReturn gst_dvdlpcmdec_link (GstPad * pad, GstPad * peer);
|
||||
static GstFlowReturn gst_dvdlpcmdec_chain_raw (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static GstFlowReturn gst_dvdlpcmdec_chain_dvd (GstPad * pad,
|
||||
GstBuffer * buffer);
|
||||
static GstPadLinkReturn gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps);
|
||||
|
||||
static GstElementStateReturn gst_dvdlpcmdec_change_state (GstElement * element);
|
||||
|
||||
|
@ -145,9 +149,10 @@ gst_dvdlpcm_reset (GstDvdLpcmDec * dvdlpcmdec)
|
|||
dvdlpcmdec->dynamic_range = 0;
|
||||
dvdlpcmdec->emphasis = FALSE;
|
||||
dvdlpcmdec->mute = FALSE;
|
||||
dvdlpcmdec->offset = 0;
|
||||
dvdlpcmdec->timestamp = 0;
|
||||
|
||||
dvdlpcmdec->header = 0;
|
||||
|
||||
GST_LOG_OBJECT (dvdlpcmdec, "Setting NULL caps on src pad");
|
||||
gst_pad_set_caps (dvdlpcmdec->srcpad, NULL);
|
||||
}
|
||||
|
@ -158,36 +163,41 @@ gst_dvdlpcmdec_init (GstDvdLpcmDec * dvdlpcmdec)
|
|||
dvdlpcmdec->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&gst_dvdlpcmdec_sink_template), "sink");
|
||||
gst_pad_set_link_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_link);
|
||||
gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain);
|
||||
gst_pad_set_setcaps_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_setcaps);
|
||||
gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->sinkpad);
|
||||
|
||||
dvdlpcmdec->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&gst_dvdlpcmdec_src_template), "src");
|
||||
gst_pad_use_fixed_caps (dvdlpcmdec->srcpad);
|
||||
gst_element_add_pad (GST_ELEMENT (dvdlpcmdec), dvdlpcmdec->srcpad);
|
||||
|
||||
gst_dvdlpcm_reset (dvdlpcmdec);
|
||||
}
|
||||
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_dvdlpcmdec_link (GstPad * pad, GstPad * peer)
|
||||
static gboolean
|
||||
gst_dvdlpcmdec_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstStructure *structure;
|
||||
gboolean res = TRUE;
|
||||
GstDvdLpcmDec *dvdlpcmdec;
|
||||
GstCaps *src_caps;
|
||||
GstCaps *caps;
|
||||
|
||||
g_return_val_if_fail (peer != NULL, GST_PAD_LINK_REFUSED);
|
||||
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_REFUSED);
|
||||
g_return_val_if_fail (caps != NULL, FALSE);
|
||||
g_return_val_if_fail (pad != NULL, FALSE);
|
||||
|
||||
dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
|
||||
|
||||
caps = gst_pad_get_caps (peer);
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
/* If we have the DVD structured LPCM (including header) */
|
||||
if (gst_structure_has_name (structure, "audio/x-private1-lpcm")) {
|
||||
gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_dvd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gst_pad_set_chain_function (dvdlpcmdec->sinkpad, gst_dvdlpcmdec_chain_raw);
|
||||
|
||||
res &= gst_structure_get_int (structure, "rate", &dvdlpcmdec->rate);
|
||||
res &= gst_structure_get_int (structure, "channels", &dvdlpcmdec->channels);
|
||||
res &= gst_structure_get_int (structure, "width", &dvdlpcmdec->width);
|
||||
|
@ -201,7 +211,6 @@ gst_dvdlpcmdec_link (GstPad * pad, GstPad * peer)
|
|||
GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't get parameters; missing caps?");
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
|
||||
/* Output width is the input width rounded up to the nearest byte */
|
||||
if (dvdlpcmdec->width == 20)
|
||||
dvdlpcmdec->out_width = 24;
|
||||
|
@ -232,9 +241,9 @@ gst_dvdlpcmdec_link (GstPad * pad, GstPad * peer)
|
|||
gst_caps_unref (src_caps);
|
||||
|
||||
if (!res)
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return FALSE;
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -253,10 +262,47 @@ update_timestamps (GstDvdLpcmDec * dvdlpcmdec, GstBuffer * buf, int samples)
|
|||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||
}
|
||||
|
||||
static void
|
||||
parse_header (GstDvdLpcmDec * dec, guint32 header)
|
||||
{
|
||||
/* We don't actually use 'dynamic range', 'mute', or 'emphasis' currently,
|
||||
* but parse them out */
|
||||
dec->dynamic_range = header & 0xff;
|
||||
|
||||
dec->mute = (header & 0x400000) != 0;
|
||||
dec->emphasis = (header & 0x800000) != 0;
|
||||
|
||||
/* These two bits tell us the bit depth */
|
||||
switch (header & 0xC000) {
|
||||
case 0x8000:
|
||||
dec->width = 24;
|
||||
dec->out_width = 24;
|
||||
break;
|
||||
case 0x4000:
|
||||
dec->width = 20;
|
||||
dec->out_width = 24;
|
||||
break;
|
||||
default:
|
||||
dec->width = 16;
|
||||
dec->out_width = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only two sample rates supported */
|
||||
if (header & 0x1000)
|
||||
dec->rate = 96000;
|
||||
else
|
||||
dec->rate = 48000;
|
||||
|
||||
/* And, of course, the number of channels (up to 8) */
|
||||
dec->channels = ((header >> 8) & 0x7) + 1;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
||||
gst_dvdlpcmdec_chain_dvd (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstDvdLpcmDec *dvdlpcmdec;
|
||||
guchar *data;
|
||||
gint64 size;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||
|
@ -266,6 +312,87 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
|
||||
|
||||
size = GST_BUFFER_SIZE (buf);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
|
||||
/* We have a 5 byte header, now.
|
||||
* The first two bytes are a (big endian) 16 bit offset into our buffer.
|
||||
* The buffer timestamp refers to this offset.
|
||||
*
|
||||
* The other three bytes are a (big endian) number in which the header is
|
||||
* encoded.
|
||||
*/
|
||||
gint first_access = (data[0] << 8) | data[1];
|
||||
guint32 header = (data[2] << 16) | (data[3] << 8) | data[2];
|
||||
GstBuffer *subbuf;
|
||||
GstFlowReturn ret;
|
||||
int off, len;
|
||||
|
||||
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)) {
|
||||
GST_DEBUG_OBJECT (dvdlpcmdec, "Failed to set caps!");
|
||||
GST_DEBUG_OBJECT (dvdlpcmdec, "Couldn't negotiate caps on src pad");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gst_caps_unref (src_caps);
|
||||
|
||||
dvdlpcmdec->header = header;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (dvdlpcmdec, "Creating sub-buffers for first_access %d",
|
||||
first_access);
|
||||
|
||||
off = 5;
|
||||
len = first_access - 1;
|
||||
|
||||
if (len > 0) {
|
||||
subbuf = gst_buffer_create_sub (buf, off, len);
|
||||
GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE;
|
||||
ret = gst_dvdlpcmdec_chain_raw (pad, subbuf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
off += len;
|
||||
len = size - len;
|
||||
|
||||
subbuf = gst_buffer_create_sub (buf, off, len);
|
||||
GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
return gst_dvdlpcmdec_chain_raw (pad, subbuf);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_dvdlpcmdec_chain_raw (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstDvdLpcmDec *dvdlpcmdec;
|
||||
guchar *data;
|
||||
gint64 size;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
|
||||
|
||||
dvdlpcmdec = GST_DVDLPCMDEC (gst_pad_get_parent (pad));
|
||||
|
||||
size = GST_BUFFER_SIZE (buf);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
|
||||
GST_LOG_OBJECT (dvdlpcmdec, "got buffer %p of size %" G_GINT64_FORMAT, buf,
|
||||
size);
|
||||
|
@ -294,12 +421,13 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
|
||||
samples = size / dvdlpcmdec->channels / 2;
|
||||
|
||||
buf = gst_buffer_make_writable (buf);
|
||||
|
||||
/* Set appropriate caps on it to pass downstream */
|
||||
gst_buffer_set_caps (buf, GST_PAD_CAPS (dvdlpcmdec->srcpad));
|
||||
|
||||
update_timestamps (dvdlpcmdec, buf, samples);
|
||||
|
||||
dvdlpcmdec->offset += size;
|
||||
gst_pad_push (dvdlpcmdec->srcpad, buf);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
@ -315,7 +443,7 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
GstFlowReturn newbufret;
|
||||
GstCaps *bufcaps = GST_PAD_CAPS (dvdlpcmdec->srcpad);
|
||||
|
||||
newbufret = gst_pad_alloc_buffer (dvdlpcmdec->srcpad, dvdlpcmdec->offset,
|
||||
newbufret = gst_pad_alloc_buffer (dvdlpcmdec->srcpad, 0,
|
||||
samples * 3, bufcaps, &outbuf);
|
||||
if (newbufret != GST_FLOW_OK) {
|
||||
GST_ELEMENT_ERROR (dvdlpcmdec, RESOURCE, FAILED, (NULL),
|
||||
|
@ -327,7 +455,7 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
|
||||
update_timestamps (dvdlpcmdec, buf, samples / dvdlpcmdec->channels);
|
||||
|
||||
src = GST_BUFFER_DATA (buf);
|
||||
src = data;
|
||||
dest = GST_BUFFER_DATA (outbuf);
|
||||
|
||||
/* Copy 20-bit LPCM format to 24-bit buffers, with 0x00 in the lowest
|
||||
|
@ -351,7 +479,6 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
dvdlpcmdec->offset += GST_BUFFER_SIZE (outbuf);
|
||||
gst_pad_push (dvdlpcmdec->srcpad, outbuf);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
@ -371,7 +498,7 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
gst_buffer_set_caps (buf, GST_PAD_CAPS (dvdlpcmdec->srcpad));
|
||||
update_timestamps (dvdlpcmdec, buf, samples);
|
||||
|
||||
src = GST_BUFFER_DATA (buf);
|
||||
src = data;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
guchar temp[9];
|
||||
|
@ -390,7 +517,6 @@ gst_dvdlpcmdec_chain (GstPad * pad, GstBuffer * buf)
|
|||
src += 12;
|
||||
}
|
||||
|
||||
dvdlpcmdec->offset += GST_BUFFER_SIZE (buf);
|
||||
gst_pad_push (dvdlpcmdec->srcpad, buf);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ struct _GstDvdLpcmDec {
|
|||
|
||||
GstPad *sinkpad,*srcpad;
|
||||
|
||||
guint32 header;
|
||||
|
||||
gint rate;
|
||||
gint channels;
|
||||
gint width;
|
||||
|
@ -52,7 +54,6 @@ struct _GstDvdLpcmDec {
|
|||
gint emphasis;
|
||||
gint mute;
|
||||
|
||||
guint64 offset;
|
||||
GstClockTime timestamp;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue