dvdlpcmdec: add support for another format

The format specification can be found here:
http://www.dvdforum.org/images/Guideline1394V10R0_20020911.pdf

Note: This format is also used for Wifi-Display.

https://bugzilla.gnome.org/show_bug.cgi?id=765807
This commit is contained in:
Michael Olbrich 2016-04-28 16:42:43 +02:00 committed by Sebastian Dröge
parent 35dc8d0f68
commit 9f51f72b37
2 changed files with 105 additions and 0 deletions

View file

@ -36,6 +36,7 @@ static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-private1-lpcm; "
"audio/x-private2-lpcm; "
"audio/x-lpcm, "
"width = (int) { 16, 20, 24 }, "
"rate = (int) { 32000, 44100, 48000, 96000 }, "
@ -239,6 +240,10 @@ gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
dvdlpcmdec->mode = GST_LPCM_DVD;
goto done;
}
if (gst_structure_has_name (structure, "audio/x-private2-lpcm")) {
dvdlpcmdec->mode = GST_LPCM_1394;
goto done;
}
dvdlpcmdec->mode = GST_LPCM_RAW;
@ -500,6 +505,102 @@ negotiation_failed:
}
}
static GstFlowReturn
gst_dvdlpcmdec_parse_1394 (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
gint * offset, gint * len)
{
guint32 header;
const guint8 *data;
data = (const guint8 *) gst_adapter_map (adapter, 4);
if (!data)
goto too_small;
header = GST_READ_UINT32_BE (data);
gst_adapter_unmap (adapter);
/* see if we have a new header */
if (header != dvdlpcmdec->header) {
GstAudioFormat format;
gint rate, channels;
if (header >> 24 != 0xa0)
goto invalid_data;
switch ((header >> 6) & 0x3) {
case 0x0:
format = GST_AUDIO_FORMAT_S16BE;
dvdlpcmdec->width = 16;
break;
default:
format = GST_AUDIO_FORMAT_UNKNOWN;
dvdlpcmdec->width = 0;
GST_WARNING ("Invalid quantization word length!");
break;
}
switch ((header >> 3) & 0x7) {
case 0x1:
rate = 44100;
break;
case 0x2:
rate = 48000;
break;
default:
rate = 0;
GST_WARNING ("Invalid audio sampling frequency!");
break;
}
switch (header & 0x7) {
case 0x0: /* 2 channels dual-mono */
case 0x1: /* 2 channles stereo */
channels = 2;
break;
default:
channels = 0;
GST_WARNING ("Invalid number of audio channels!");
break;
}
gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format);
if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
goto negotiation_failed;
dvdlpcmdec->header = header;
}
*offset = 4;
*len = gst_adapter_available (adapter) - 4;
return GST_FLOW_OK;
/* ERRORS */
too_small:
{
/* Buffer is too small */
GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
("Invalid data found parsing LPCM packet"),
("LPCM packet was too small. Dropping"));
*offset = gst_adapter_available (adapter);
return GST_FLOW_EOS;
}
invalid_data:
{
GST_ELEMENT_WARNING (dvdlpcmdec, STREAM, DECODE,
("Invalid data found parsing LPCM packet"),
("LPCM packet contains invalid sub_stream_id."));
return GST_FLOW_ERROR;
}
negotiation_failed:
{
GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
("Failed to configure output format"));
return GST_FLOW_NOT_NEGOTIATED;
}
}
static GstFlowReturn
gst_dvdlpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
gint * offset, gint * len)
@ -517,6 +618,9 @@ gst_dvdlpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
case GST_LPCM_DVD:
return gst_dvdlpcmdec_parse_dvd (dvdlpcmdec, adapter, offset, len);
case GST_LPCM_1394:
return gst_dvdlpcmdec_parse_1394 (dvdlpcmdec, adapter, offset, len);
}
return GST_FLOW_ERROR;
}

View file

@ -45,6 +45,7 @@ typedef enum {
GST_LPCM_UNKNOWN,
GST_LPCM_RAW,
GST_LPCM_DVD,
GST_LPCM_1394
} GstDvdLpcmMode;
struct _GstDvdLpcmDec {