gst_plugins_good/gst/wavenc/gstwavenc.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
--- a/gst_plugins_good/gst/wavenc/gstwavenc.c	Wed Mar 24 17:58:42 2010 -0500
+++ b/gst_plugins_good/gst/wavenc/gstwavenc.c	Wed Mar 24 18:04:17 2010 -0500
@@ -24,24 +24,17 @@
 #include "config.h"
 #endif
 
-
-
 #include <string.h>
 #include "gstwavenc.h"
-//#include "riff.h" rj
+#include "riff.h"
 
-#include "gst/riff/riff-ids.h"
-#include "gst/riff/riff-media.h"
-#include <gst/gst-i18n-plugin.h>
 
 #ifdef __SYMBIAN32__
 #include<gst/gstinfo.h>
 #endif
 
 GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
-#define GST_CAT_DEFAULT (wavenc_debug) //rj
-
-#define WAVE_FORMAT_PCM 0x0001
+#define GST_CAT_DEFAULT wavenc_debug
 
 struct riff_struct
 {
@@ -88,6 +81,22 @@
     "rate = (int) [ 1, MAX ], "          \
     "channels = (int) [ 1, 2 ], "        \
     "endianness = (int) LITTLE_ENDIAN, " \
+    "width = (int) 32, "                 \
+    "depth = (int) 32, "                 \
+    "signed = (boolean) true"            \
+    "; "                                 \
+    "audio/x-raw-int, "                  \
+    "rate = (int) [ 1, MAX ], "          \
+    "channels = (int) [ 1, 2 ], "        \
+    "endianness = (int) LITTLE_ENDIAN, " \
+    "width = (int) 24, "                 \
+    "depth = (int) 24, "                 \
+    "signed = (boolean) true"            \
+    "; "                                 \
+    "audio/x-raw-int, "                  \
+    "rate = (int) [ 1, MAX ], "          \
+    "channels = (int) [ 1, 2 ], "        \
+    "endianness = (int) LITTLE_ENDIAN, " \
     "width = (int) 16, "                 \
     "depth = (int) 16, "                 \
     "signed = (boolean) true"            \
@@ -96,6 +105,25 @@
     "rate = (int) [ 1, MAX ], "          \
     "channels = (int) [ 1, 2 ], "        \
     "width = (int) 8, "                  \
+    "depth = (int) 8, "                  \
+    "signed = (boolean) false"           \
+    "; "                                 \
+    "audio/x-raw-float, "                \
+    "rate = (int) [ 1, MAX ], "          \
+    "channels = (int) [ 1, 2 ], "        \
+    "endianness = (int) LITTLE_ENDIAN, " \
+    "width = (int) { 32, 64 }; "         \
+    "audio/x-alaw, "                     \
+    "rate = (int) [ 8000, 192000 ], "    \
+    "channels = (int) [ 1, 2 ], "        \
+    "width = (int) 8, "                  \
+    "depth = (int) 8, "                  \
+    "signed = (boolean) false; "         \
+    "audio/x-mulaw, "                    \
+    "rate = (int) [ 8000, 192000 ], "    \
+    "channels = (int) [ 1, 2 ], "        \
+    "width = (int) 8, "                  \
+    "depth = (int) 8, "                  \
     "signed = (boolean) false"
 
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
@@ -110,16 +138,7 @@
     GST_STATIC_CAPS ("audio/x-wav")
     );
 
-#ifndef __SYMBIAN32__  //rj
 GST_BOILERPLATE (GstWavEnc, gst_wavenc, GstElement, GST_TYPE_ELEMENT);
-#endif
-
-//rj
-static void gst_wavenc_base_init (gpointer g_class);
-static void gst_wavenc_class_init (GstWavEncClass * klass);
-static void gst_wavenc_init (GstWavEnc * wavenc, GstWavEncClass * klass);
-static GstElementClass *parent_class = NULL;
-//rj
 
 static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstBuffer * buf);
 static gboolean gst_wavenc_event (GstPad * pad, GstEvent * event);
@@ -127,34 +146,6 @@
     GstStateChange transition);
 static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps);
 
-
-
-
-GType gst_wavenc_get_type (void)
-{
-  static GType wavenc_type = 0;
-
-  if (!wavenc_type) {
-    static const GTypeInfo wavenc_info = {
-      sizeof (GstWavEncClass),
-      gst_wavenc_base_init,
-      NULL,
-      (GClassInitFunc) gst_wavenc_class_init,
-      NULL,
-      NULL,
-      sizeof (GstWavEnc),
-      0,
-      (GInstanceInitFunc) gst_wavenc_init,
-    };
-
-    wavenc_type =
-        g_type_register_static (GST_TYPE_ELEMENT, "GstWavEnc",
-        &wavenc_info, 0);
-  }
-  return wavenc_type;
-}
-
-
 static void
 gst_wavenc_base_init (gpointer g_class)
 {
@@ -176,8 +167,6 @@
   GstElementClass *element_class;
 
   element_class = (GstElementClass *) klass;
-  
-  parent_class = g_type_class_peek_parent (klass);//rj
 
   element_class->change_state = GST_DEBUG_FUNCPTR (gst_wavenc_change_state);
 }
@@ -203,7 +192,6 @@
 
 #define WAV_HEADER_LEN 44
 
-/* FIXME: we are probably not handling depth != width correctly here */
 static GstBuffer *
 gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
 {
@@ -216,23 +204,23 @@
   memset (header, 0, WAV_HEADER_LEN);
 
   wave.common.wChannels = wavenc->channels;
-  wave.common.wBitsPerSample = wavenc->depth;
+  wave.common.wBitsPerSample = wavenc->width;
   wave.common.dwSamplesPerSec = wavenc->rate;
 
   /* Fill out our wav-header with some information */
   memcpy (wave.riff.id, "RIFF", 4);
+  //g_printf("before wave.riff.len %d \n" ,wave.riff.len);
   wave.riff.len = audio_data_size + WAV_HEADER_LEN - 8;
+  //g_printf("after wave.riff.len %d \n" ,wave.riff.len);
   memcpy (wave.riff.wav_id, "WAVE", 4);
 
   memcpy (wave.format.id, "fmt ", 4);
   wave.format.len = 16;
 
-  wave.common.wFormatTag = WAVE_FORMAT_PCM;
+  wave.common.wFormatTag = wavenc->format;
+  wave.common.wBlockAlign = (wavenc->width / 8) * wave.common.wChannels;
   wave.common.dwAvgBytesPerSec =
-      wave.common.wChannels * wave.common.dwSamplesPerSec *
-      (wave.common.wBitsPerSample >> 3);
-  wave.common.wBlockAlign =
-      wave.common.wChannels * (wave.common.wBitsPerSample >> 3);
+      wave.common.wBlockAlign * wave.common.dwSamplesPerSec;
 
   memcpy (wave.data.id, "data", 4);
   wave.data.len = audio_data_size;
@@ -287,7 +275,8 @@
 {
   GstWavEnc *wavenc;
   GstStructure *structure;
-  gint chans, rate, width, depth;
+  const gchar *name;
+  gint chans, rate, width;
 
   wavenc = GST_WAVENC (gst_pad_get_parent (pad));
 
@@ -299,21 +288,45 @@
   GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps);
 
   structure = gst_caps_get_structure (caps, 0);
+  name = gst_structure_get_name (structure);
+
   if (!gst_structure_get_int (structure, "channels", &chans) ||
-      !gst_structure_get_int (structure, "rate", &rate) ||
-      !gst_structure_get_int (structure, "width", &width) ||
-      (width != 8 && !gst_structure_get_int (structure, "depth", &depth))) {
+      !gst_structure_get_int (structure, "rate", &rate)) {
     GST_WARNING_OBJECT (wavenc, "caps incomplete");
     goto fail;
   }
 
+  if (strcmp (name, "audio/x-raw-int") == 0) {
+    if (!gst_structure_get_int (structure, "width", &width)) {
+      GST_WARNING_OBJECT (wavenc, "caps incomplete");
+      goto fail;
+    }
+    wavenc->format = GST_RIFF_WAVE_FORMAT_PCM;
+    wavenc->width = width;
+  } else if (strcmp (name, "audio/x-raw-float") == 0) {
+    if (!gst_structure_get_int (structure, "width", &width)) {
+      GST_WARNING_OBJECT (wavenc, "caps incomplete");
+      goto fail;
+    }
+    wavenc->format = GST_RIFF_WAVE_FORMAT_FLOAT;
+    wavenc->width = width;
+  } else if (strcmp (name, "audio/x-alaw") == 0) {
+    wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW;
+    wavenc->width = 8;
+  } else if (strcmp (name, "audio/x-mulaw") == 0) {
+    wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW;
+    wavenc->width = 8;
+  } else {
+    GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name);
+    goto fail;
+  }
+
   wavenc->channels = chans;
-  wavenc->width = width;
-  wavenc->depth = (width == 8) ? 8 : depth;
   wavenc->rate = rate;
 
-  GST_LOG_OBJECT (wavenc, "accepted caps: chans=%u width=%u depth=%u rate=%u",
-      wavenc->channels, wavenc->width, wavenc->depth, wavenc->rate);
+  GST_LOG_OBJECT (wavenc,
+      "accepted caps: format=0x%04x chans=%u width=%u rate=%u",
+      wavenc->format, wavenc->channels, wavenc->width, wavenc->rate);
 
   gst_object_unref (wavenc);
   return TRUE;
@@ -625,6 +638,9 @@
       /* write header with correct length values */
       gst_wavenc_push_header (wavenc, wavenc->length);
 
+      /* we're done with this file */
+      wavenc->finished_properly = TRUE;
+
       /* and forward the EOS event */
       res = gst_pad_event_default (pad, event);
       break;
@@ -656,6 +672,9 @@
      * header when we get EOS and know the exact length */
     flow = gst_wavenc_push_header (wavenc, 0x7FFF0000);
 
+    /* starting a file, means we have to finish it properly */
+    wavenc->finished_properly = FALSE;
+
     if (flow != GST_FLOW_OK)
       return flow;
 
@@ -663,8 +682,6 @@
     wavenc->sent_header = TRUE;
   }
 
-  wavenc->length += GST_BUFFER_SIZE (buf);
-
   GST_LOG_OBJECT (wavenc, "pushing %u bytes raw audio, ts=%" GST_TIME_FORMAT,
       GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
 
@@ -673,6 +690,8 @@
   GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->length;
   GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
 
+  wavenc->length += GST_BUFFER_SIZE (buf);
+
   flow = gst_pad_push (wavenc->srcpad, buf);
 
   return flow;
@@ -686,12 +705,14 @@
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
+      wavenc->format = 0;
       wavenc->channels = 0;
       wavenc->width = 0;
-      wavenc->depth = 0;
       wavenc->rate = 0;
       wavenc->length = 0;
       wavenc->sent_header = FALSE;
+      /* its true because we haven't writen anything */
+      wavenc->finished_properly = TRUE;
       break;
     default:
       break;
@@ -701,13 +722,26 @@
   if (ret != GST_STATE_CHANGE_SUCCESS)
     return ret;
 
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (!wavenc->finished_properly) {
+        GST_ELEMENT_WARNING (wavenc, STREAM, MUX,
+            ("Wav stream not finished properly"),
+            ("Wav stream not finished properly, no EOS received "
+                "before shutdown"));
+      }
+      break;
+    default:
+      break;
+  }
+
   return ret;
 }
 
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  return gst_element_register (plugin, "wavenc", GST_RANK_NONE,
+  return gst_element_register (plugin, "wavenc", GST_RANK_PRIMARY,
       GST_TYPE_WAVENC);
 }