ext/flac/gstflacdec.c: Support decoding of all depths between 4 and 32 bits and read...
authorSebastian Dröge <slomo@circular-chaos.org>
Sun, 3 Aug 2008 11:38:22 +0000 (11:38 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Sun, 3 Aug 2008 11:38:22 +0000 (11:38 +0000)
Original commit message from CVS:
* ext/flac/gstflacdec.c: (gst_flac_dec_metadata_callback),
(gst_flac_dec_write):
Support decoding of all depths between 4 and 32 bits and read the
depth from the streaminfo header if needed. Also support all sampling
rates between 1 and 655350 Hz.
* ext/flac/gstflacenc.c:
(gst_flac_enc_caps_append_structure_with_widths),
(gst_flac_enc_sink_getcaps), (gst_flac_enc_sink_setcaps),
(gst_flac_enc_chain):
* ext/flac/gstflacenc.h:
Support encoding in all bit depths supported by the streamable
subformat (i.e. 8, 12, 16, 20 and 24 bits) and all sampling rates
between 1 Hz and 655350 Hz.

ChangeLog
ext/flac/gstflacdec.c
ext/flac/gstflacenc.c
ext/flac/gstflacenc.h

index 548fbe18c60728220cd5ffd7b55a503a04cd4de9..cc564bd510602fb58d99c05a304b3ca588385821 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-08-03  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
+
+       * ext/flac/gstflacdec.c: (gst_flac_dec_metadata_callback),
+       (gst_flac_dec_write):
+       Support decoding of all depths between 4 and 32 bits and read the
+       depth from the streaminfo header if needed. Also support all sampling
+       rates between 1 and 655350 Hz.
+
+       * ext/flac/gstflacenc.c:
+       (gst_flac_enc_caps_append_structure_with_widths),
+       (gst_flac_enc_sink_getcaps), (gst_flac_enc_sink_setcaps),
+       (gst_flac_enc_chain):
+       * ext/flac/gstflacenc.h:
+       Support encoding in all bit depths supported by the streamable
+       subformat (i.e. 8, 12, 16, 20 and 24 bits) and all sampling rates
+       between 1 Hz and 655350 Hz.
+
 2008-08-03  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
 
        * ext/flac/gstflacenc.c: (gst_flac_enc_init),
index 5d65c837fad4b7319cf0ff65e6ee722b7d02cb06..7b8e381f8625931851a9fc68e23b2111edd55d8b 100644 (file)
@@ -218,8 +218,8 @@ GST_BOILERPLATE (GstFlacDec, gst_flac_dec, GstElement, GST_TYPE_ELEMENT);
     "endianness = (int) BYTE_ORDER, "                     \
     "signed = (boolean) true, "                           \
     "width = (int) { 8, 16, 32 }, "                       \
-    "depth = (int) { 8, 12, 16, 20, 24, 32 }, "           \
-    "rate = (int) [ 8000, 96000 ], "                      \
+    "depth = (int) [ 4, 32 ], "                           \
+    "rate = (int) [ 1, 655350 ], "                        \
     "channels = (int) [ 1, 8 ]"
 static void
 gst_flac_dec_base_init (gpointer g_class)
@@ -680,6 +680,7 @@ gst_flac_dec_metadata_callback (GstFlacDec * flacdec,
       flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
       flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
       flacdec->sample_rate = metadata->data.stream_info.sample_rate;
+      flacdec->depth = metadata->data.stream_info.bits_per_sample;
 
       GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
           flacdec->min_blocksize, flacdec->max_blocksize);
@@ -997,19 +998,12 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
     const FLAC__int32 * const buffer[])
 {
   GstFlowReturn ret = GST_FLOW_OK;
-
   GstBuffer *outbuf;
-
   guint depth = frame->header.bits_per_sample;
-
   guint width;
-
   guint channels = frame->header.channels;
-
   guint samples = frame->header.blocksize;
-
   guint j, i;
-
   GstClockTime next;
 
   switch (depth) {
@@ -1024,6 +1018,23 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
     case 24:
     case 32:
       width = 32;
+      break;
+    case 0:
+      if (flacdec->depth < 4 || flacdec->depth > 32) {
+        GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
+            flacdec->depth);
+        ret = GST_FLOW_ERROR;
+        goto done;
+      }
+
+      depth = flacdec->depth;
+      if (depth < 9)
+        width = 8;
+      else if (depth < 17)
+        width = 16;
+      else
+        width = 32;
+
       break;
     default:
       GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth);
@@ -1101,7 +1112,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
 
   GST_BUFFER_DURATION (outbuf) = next - GST_BUFFER_TIMESTAMP (outbuf);
 
-  if (depth == 8) {
+  if (width == 8) {
     gint8 *outbuffer = (gint8 *) GST_BUFFER_DATA (outbuf);
 
     for (i = 0; i < samples; i++) {
@@ -1109,7 +1120,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
         *outbuffer++ = (gint8) buffer[j][i];
       }
     }
-  } else if (depth == 12 || depth == 16) {
+  } else if (width == 16) {
     gint16 *outbuffer = (gint16 *) GST_BUFFER_DATA (outbuf);
 
     for (i = 0; i < samples; i++) {
@@ -1117,7 +1128,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
         *outbuffer++ = (gint16) buffer[j][i];
       }
     }
-  } else if (depth == 20 || depth == 24 || depth == 32) {
+  } else if (width == 32) {
     gint32 *outbuffer = (gint32 *) GST_BUFFER_DATA (outbuf);
 
     for (i = 0; i < samples; i++) {
index bcd51556dc269a4dfb2fc81bb9aad21609ad5517..475d7a67e6cd35486dba7e1ec0d54261b9f91185 100644 (file)
@@ -21,9 +21,6 @@
  *  - we assume timestamps start from 0 and that we get a perfect stream; we
  *    don't handle non-zero starts and mid-stream discontinuities, esp. not if
  *    we're muxing into ogg
- *  - need to support wider caps, 4-32 bit pcm
- *    http://flac.sourceforge.net/faq.html#general__channels
- *    it also support sampling rate from 1Hz - 655350Hz
  */
 
 #ifdef HAVE_CONFIG_H
@@ -87,12 +84,26 @@ GST_ELEMENT_DETAILS ("FLAC audio encoder",
     "Wim Taymans <wim.taymans@chello.be>");
 
 #define FLAC_SINK_CAPS \
+  "audio/x-raw-int, "               \
+  "endianness = (int) BYTE_ORDER, " \
+  "signed = (boolean) TRUE, "       \
+  "width = (int) 8, "               \
+  "depth = (int) 8, "               \
+  "rate = (int) [ 1, 655350 ], "    \
+  "channels = (int) [ 1, 8 ]; "     \
   "audio/x-raw-int, "               \
   "endianness = (int) BYTE_ORDER, " \
   "signed = (boolean) TRUE, "       \
   "width = (int) 16, "              \
-  "depth = (int) 16, "              \
-  "rate = (int) [ 8000, 96000 ], " \
+  "depth = (int) { 12, 16 }, "      \
+  "rate = (int) [ 1, 655350 ], "    \
+  "channels = (int) [ 1, 8 ]; "     \
+  "audio/x-raw-int, "               \
+  "endianness = (int) BYTE_ORDER, " \
+  "signed = (boolean) TRUE, "       \
+  "width = (int) 32, "              \
+  "depth = (int) { 20, 24 }, "      \
+  "rate = (int) [ 1, 655350 ], "    \
   "channels = (int) [ 1, 8 ]"
 
 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
@@ -446,6 +457,49 @@ gst_flac_enc_set_metadata (GstFlacEnc * flacenc)
   gst_tag_list_free (copy);
 }
 
+static void
+gst_flac_enc_caps_append_structure_with_widths (GstCaps * caps,
+    GstStructure * s)
+{
+  GstStructure *tmp;
+  GValue list = { 0, };
+  GValue depth = { 0, };
+
+
+  tmp = gst_structure_copy (s);
+  gst_structure_set (tmp, "width", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL);
+  gst_caps_append_structure (caps, tmp);
+
+  tmp = gst_structure_copy (s);
+
+  g_value_init (&depth, G_TYPE_INT);
+  g_value_init (&list, GST_TYPE_LIST);
+  g_value_set_int (&depth, 12);
+  gst_value_list_append_value (&list, &depth);
+  g_value_set_int (&depth, 16);
+  gst_value_list_append_value (&list, &depth);
+
+  gst_structure_set (tmp, "width", G_TYPE_INT, 16, NULL);
+  gst_structure_set_value (tmp, "depth", &list);
+  gst_caps_append_structure (caps, tmp);
+
+  g_value_reset (&list);
+
+  tmp = s;
+
+  g_value_set_int (&depth, 20);
+  gst_value_list_append_value (&list, &depth);
+  g_value_set_int (&depth, 24);
+  gst_value_list_append_value (&list, &depth);
+
+  gst_structure_set (tmp, "width", G_TYPE_INT, 32, NULL);
+  gst_structure_set_value (tmp, "depth", &list);
+  gst_caps_append_structure (caps, tmp);
+
+  g_value_unset (&list);
+  g_value_unset (&depth);
+}
+
 static GstCaps *
 gst_flac_enc_sink_getcaps (GstPad * pad)
 {
@@ -460,12 +514,11 @@ gst_flac_enc_sink_getcaps (GstPad * pad)
 
     ret = gst_caps_new_empty ();
 
-    gst_caps_append_structure (ret, gst_structure_new ("audio/x-raw-int",
+    gst_flac_enc_caps_append_structure_with_widths (ret,
+        gst_structure_new ("audio/x-raw-int",
             "endianness", G_TYPE_INT, G_BYTE_ORDER,
             "signed", G_TYPE_BOOLEAN, TRUE,
-            "width", G_TYPE_INT, 16,
-            "depth", G_TYPE_INT, 16,
-            "rate", GST_TYPE_INT_RANGE, 8000, 96000,
+            "rate", GST_TYPE_INT_RANGE, 1, 655350,
             "channels", GST_TYPE_INT_RANGE, 1, 2, NULL));
 
     for (i = 3; i <= 8; i++) {
@@ -485,14 +538,12 @@ gst_flac_enc_sink_getcaps (GstPad * pad)
       s = gst_structure_new ("audio/x-raw-int",
           "endianness", G_TYPE_INT, G_BYTE_ORDER,
           "signed", G_TYPE_BOOLEAN, TRUE,
-          "width", G_TYPE_INT, 16,
-          "depth", G_TYPE_INT, 16,
-          "rate", GST_TYPE_INT_RANGE, 8000, 96000,
+          "rate", GST_TYPE_INT_RANGE, 1, 655350,
           "channels", G_TYPE_INT, i, NULL);
       gst_structure_set_value (s, "channel-positions", &positions);
       g_value_unset (&positions);
 
-      gst_caps_append_structure (ret, s);
+      gst_flac_enc_caps_append_structure_with_widths (ret, s);
     }
   }
 
@@ -539,6 +590,7 @@ gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
   }
 
   flacenc->channels = chans;
+  flacenc->width = width;
   flacenc->depth = depth;
   flacenc->sample_rate = rate;
 
@@ -1019,7 +1071,7 @@ gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
   GstFlacEnc *flacenc;
   FLAC__int32 *data;
   gulong insize;
-  gint samples, depth;
+  gint samples, width;
   gulong i;
   FLAC__bool res;
 
@@ -1029,21 +1081,26 @@ gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
   if (G_UNLIKELY (flacenc->depth == 0))
     return GST_FLOW_NOT_NEGOTIATED;
 
-  depth = flacenc->depth;
+  width = flacenc->width;
 
   insize = GST_BUFFER_SIZE (buffer);
-  samples = insize / ((depth + 7) >> 3);
+  samples = insize / (width >> 3);
 
   data = g_malloc (samples * sizeof (FLAC__int32));
 
-  if (depth == 8) {
+  if (width == 8) {
     gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
 
     for (i = 0; i < samples; i++)
       data[i] = (FLAC__int32) indata[i];
-  } else if (depth == 16) {
+  } else if (width == 16) {
     gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
 
+    for (i = 0; i < samples; i++)
+      data[i] = (FLAC__int32) indata[i];
+  } else if (width == 32) {
+    gint32 *indata = (gint32 *) GST_BUFFER_DATA (buffer);
+
     for (i = 0; i < samples; i++)
       data[i] = (FLAC__int32) indata[i];
   } else {
index a7bbd46abf4cc20d39ccc322938186a9228ebbfa..016a56b6162d1f0997322466e6f244acb39d6720 100644 (file)
@@ -58,6 +58,7 @@ struct _GstFlacEnc {
   guint64        samples_written;
   gboolean       eos;
   gint           channels;
+  gint           width;
   gint           depth;
   gint           sample_rate;
   gboolean       negotiated;