summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivia Nikolaidou <vivia@ahiru.eu>2017-07-05 18:58:35 +0300
committerSebastian Dröge <sebastian@centricular.com>2017-07-05 19:17:59 +0300
commitcd59f39c2c62cab1b2d23830cb108a271812a3c5 (patch)
tree44f26b839390ad74addd38b6ecf1a3c86e501d8f
parentec24f4c9f2799ecd2a6b89b793b188a3fa2ae25d (diff)
dvdlpcmdec: Added support for Blu-Ray audio
https://bugzilla.gnome.org/show_bug.cgi?id=784552
-rw-r--r--gst/dvdlpcmdec/gstdvdlpcmdec.c219
-rw-r--r--gst/dvdlpcmdec/gstdvdlpcmdec.h3
2 files changed, 214 insertions, 8 deletions
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.c b/gst/dvdlpcmdec/gstdvdlpcmdec.c
index a4020075..8ac6abb1 100644
--- a/gst/dvdlpcmdec/gstdvdlpcmdec.c
+++ b/gst/dvdlpcmdec/gstdvdlpcmdec.c
@@ -37,6 +37,7 @@ static GstStaticPadTemplate gst_dvdlpcmdec_sink_template =
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-private1-lpcm; "
"audio/x-private2-lpcm; "
+ "audio/x-private-ts-lpcm; "
"audio/x-lpcm, "
"width = (int) { 16, 20, 24 }, "
"rate = (int) { 32000, 44100, 48000, 96000 }, "
@@ -152,6 +153,74 @@ static const GstAudioChannelPosition channel_positions[][8] = {
{GST_AUDIO_CHANNEL_POSITION_INVALID}
};
+static const GstAudioChannelPosition bluray_channel_positions[][8] = {
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ /* mono */
+ {GST_AUDIO_CHANNEL_POSITION_MONO},
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ /* stereo */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
+ /* surround */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER},
+ /* 2.1 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
+ /* 4.0 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
+ /* 2.2 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
+ /* 5.0 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
+ /* 5.1 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE1},
+ /* 7.0 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
+ /* 7.1 */
+ {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE1},
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID},
+ /* invalid */
+ {GST_AUDIO_CHANNEL_POSITION_INVALID}
+};
+
static void
gst_dvdlpcmdec_send_tags (GstDvdLpcmDec * dvdlpcmdec)
{
@@ -192,20 +261,21 @@ gst_dvdlpcmdec_set_output_format (GstDvdLpcmDec * dvdlpcmdec)
static void
gst_dvdlpcmdec_update_audio_formats (GstDvdLpcmDec * dec, gint channels,
- gint rate, GstAudioFormat format)
+ gint rate, GstAudioFormat format, guint8 channel_indicator,
+ const GstAudioChannelPosition positions[][8])
{
- GST_DEBUG_OBJECT (dec, "got channles = %d, rate = %d, format = %d", channels,
+ GST_DEBUG_OBJECT (dec, "got channels = %d, rate = %d, format = %d", channels,
rate, format);
/* Reorder the channel positions and set the default into for the audio */
if (channels < 9
- && channel_positions[channels - 1][0] !=
+ && positions[channel_indicator][0] !=
GST_AUDIO_CHANNEL_POSITION_INVALID) {
const GstAudioChannelPosition *position;
GstAudioChannelPosition sorted_position[8];
guint c;
- position = channel_positions[channels - 1];
+ position = positions[channel_indicator];
for (c = 0; c < channels; ++c)
sorted_position[c] = position[c];
gst_audio_channel_positions_to_valid_order (sorted_position, channels);
@@ -244,6 +314,10 @@ gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
dvdlpcmdec->mode = GST_LPCM_1394;
goto done;
}
+ if (gst_structure_has_name (structure, "audio/x-private-ts-lpcm")) {
+ dvdlpcmdec->mode = GST_LPCM_BLURAY;
+ goto done;
+ }
dvdlpcmdec->mode = GST_LPCM_RAW;
@@ -272,7 +346,8 @@ gst_dvdlpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
break;
}
- gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format);
+ gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
+ channels - 1, channel_positions);
dvdlpcmdec->width = width;
@@ -344,7 +419,8 @@ parse_header (GstDvdLpcmDec * dec, guint32 header)
/* And, of course, the number of channels (up to 8) */
channels = ((header >> 8) & 0x7) + 1;
- gst_dvdlpcmdec_update_audio_formats (dec, channels, rate, format);
+ gst_dvdlpcmdec_update_audio_formats (dec, channels, rate, format,
+ channels - 1, channel_positions);
}
static GstFlowReturn
@@ -506,6 +582,131 @@ negotiation_failed:
}
static GstFlowReturn
+gst_dvdlpcmdec_parse_bluray (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
+ gint * offset, gint * len)
+{
+ guint32 header;
+ const guint8 *data;
+ guint8 channel_indicator;
+
+ 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;
+
+ switch ((header >> 6) & 0x3) {
+ case 0x1:
+ format = GST_AUDIO_FORMAT_S16BE;
+ dvdlpcmdec->width = 16;
+ break;
+ case 0x2:
+ format = GST_AUDIO_FORMAT_S24BE;
+ dvdlpcmdec->width = 20;
+ break;
+ case 0x3:
+ format = GST_AUDIO_FORMAT_S24BE;
+ dvdlpcmdec->width = 24;
+ break;
+ default:
+ format = GST_AUDIO_FORMAT_UNKNOWN;
+ dvdlpcmdec->width = 0;
+ GST_WARNING ("Invalid sample depth!");
+ break;
+ }
+
+ switch ((header >> 8) & 0xf) {
+ case 0x1:
+ rate = 48000;
+ break;
+ case 0x4:
+ rate = 96000;
+ break;
+ case 0x5:
+ rate = 192000;
+ break;
+ default:
+ rate = 0;
+ GST_WARNING ("Invalid audio sampling frequency!");
+ break;
+ }
+ channel_indicator = (header >> 12) & 0xf;
+ switch (channel_indicator) {
+ case 0x1:
+ channels = 1;
+ break;
+ case 0x3:
+ channels = 2;
+ break;
+ case 0x4:
+ case 0x5:
+ channels = 3;
+ break;
+ case 0x6:
+ case 0x7:
+ channels = 4;
+ break;
+ case 0x8:
+ channels = 5;
+ break;
+ case 0x9:
+ channels = 6;
+ break;
+ case 0xa:
+ channels = 7;
+ break;
+ case 0xb:
+ channels = 8;
+ break;
+ default:
+ channels = 0;
+ GST_WARNING ("Invalid number of audio channels!");
+ break;
+ }
+ GST_DEBUG_OBJECT (dvdlpcmdec, "got channels %d rate %d format %s",
+ channels, rate, gst_audio_format_to_string (format));
+
+ gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
+ channel_indicator, bluray_channel_positions);
+
+ 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;
+ }
+negotiation_failed:
+ {
+ GST_ELEMENT_ERROR (dvdlpcmdec, STREAM, FORMAT, (NULL),
+ ("Failed to configure output format"));
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+}
+
+static GstFlowReturn
gst_dvdlpcmdec_parse_1394 (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
gint * offset, gint * len)
{
@@ -563,7 +764,8 @@ gst_dvdlpcmdec_parse_1394 (GstDvdLpcmDec * dvdlpcmdec, GstAdapter * adapter,
break;
}
- gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format);
+ gst_dvdlpcmdec_update_audio_formats (dvdlpcmdec, channels, rate, format,
+ channels - 1, channel_positions);
if (!gst_dvdlpcmdec_set_output_format (dvdlpcmdec))
goto negotiation_failed;
@@ -621,6 +823,9 @@ gst_dvdlpcmdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter,
case GST_LPCM_1394:
return gst_dvdlpcmdec_parse_1394 (dvdlpcmdec, adapter, offset, len);
+
+ case GST_LPCM_BLURAY:
+ return gst_dvdlpcmdec_parse_bluray (dvdlpcmdec, adapter, offset, len);
}
return GST_FLOW_ERROR;
}
diff --git a/gst/dvdlpcmdec/gstdvdlpcmdec.h b/gst/dvdlpcmdec/gstdvdlpcmdec.h
index 7f3d0c9c..3bdce3f0 100644
--- a/gst/dvdlpcmdec/gstdvdlpcmdec.h
+++ b/gst/dvdlpcmdec/gstdvdlpcmdec.h
@@ -45,7 +45,8 @@ typedef enum {
GST_LPCM_UNKNOWN,
GST_LPCM_RAW,
GST_LPCM_DVD,
- GST_LPCM_1394
+ GST_LPCM_1394,
+ GST_LPCM_BLURAY
} GstDvdLpcmMode;
struct _GstDvdLpcmDec {