gst_plugins_good/gst/wavenc/gstwavenc.c
branchRCL_3
changeset 29 567bb019e3e3
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
6:9b2c3c7a1a9c 29:567bb019e3e3
    22 
    22 
    23 #ifdef HAVE_CONFIG_H
    23 #ifdef HAVE_CONFIG_H
    24 #include "config.h"
    24 #include "config.h"
    25 #endif
    25 #endif
    26 
    26 
    27 
       
    28 
       
    29 #include <string.h>
    27 #include <string.h>
    30 #include "gstwavenc.h"
    28 #include "gstwavenc.h"
    31 //#include "riff.h" rj
    29 #include "riff.h"
    32 
    30 
    33 #include "gst/riff/riff-ids.h"
       
    34 #include "gst/riff/riff-media.h"
       
    35 #include <gst/gst-i18n-plugin.h>
       
    36 
    31 
    37 #ifdef __SYMBIAN32__
    32 #ifdef __SYMBIAN32__
    38 #include<gst/gstinfo.h>
    33 #include<gst/gstinfo.h>
    39 #endif
    34 #endif
    40 
    35 
    41 GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
    36 GST_DEBUG_CATEGORY_STATIC (wavenc_debug);
    42 #define GST_CAT_DEFAULT (wavenc_debug) //rj
    37 #define GST_CAT_DEFAULT wavenc_debug
    43 
       
    44 #define WAVE_FORMAT_PCM 0x0001
       
    45 
    38 
    46 struct riff_struct
    39 struct riff_struct
    47 {
    40 {
    48   guint8 id[4];                 /* RIFF */
    41   guint8 id[4];                 /* RIFF */
    49   guint32 len;
    42   guint32 len;
    82 
    75 
    83 /* FIXME: mono doesn't produce correct files it seems, at least mplayer xruns */
    76 /* FIXME: mono doesn't produce correct files it seems, at least mplayer xruns */
    84 /* Max. of two channels, more channels need WAVFORMATEX with
    77 /* Max. of two channels, more channels need WAVFORMATEX with
    85  * channel layout, which we do not support yet */
    78  * channel layout, which we do not support yet */
    86 #define SINK_CAPS \
    79 #define SINK_CAPS \
       
    80     "audio/x-raw-int, "                  \
       
    81     "rate = (int) [ 1, MAX ], "          \
       
    82     "channels = (int) [ 1, 2 ], "        \
       
    83     "endianness = (int) LITTLE_ENDIAN, " \
       
    84     "width = (int) 32, "                 \
       
    85     "depth = (int) 32, "                 \
       
    86     "signed = (boolean) true"            \
       
    87     "; "                                 \
       
    88     "audio/x-raw-int, "                  \
       
    89     "rate = (int) [ 1, MAX ], "          \
       
    90     "channels = (int) [ 1, 2 ], "        \
       
    91     "endianness = (int) LITTLE_ENDIAN, " \
       
    92     "width = (int) 24, "                 \
       
    93     "depth = (int) 24, "                 \
       
    94     "signed = (boolean) true"            \
       
    95     "; "                                 \
    87     "audio/x-raw-int, "                  \
    96     "audio/x-raw-int, "                  \
    88     "rate = (int) [ 1, MAX ], "          \
    97     "rate = (int) [ 1, MAX ], "          \
    89     "channels = (int) [ 1, 2 ], "        \
    98     "channels = (int) [ 1, 2 ], "        \
    90     "endianness = (int) LITTLE_ENDIAN, " \
    99     "endianness = (int) LITTLE_ENDIAN, " \
    91     "width = (int) 16, "                 \
   100     "width = (int) 16, "                 \
    94     "; "                                 \
   103     "; "                                 \
    95     "audio/x-raw-int, "                  \
   104     "audio/x-raw-int, "                  \
    96     "rate = (int) [ 1, MAX ], "          \
   105     "rate = (int) [ 1, MAX ], "          \
    97     "channels = (int) [ 1, 2 ], "        \
   106     "channels = (int) [ 1, 2 ], "        \
    98     "width = (int) 8, "                  \
   107     "width = (int) 8, "                  \
       
   108     "depth = (int) 8, "                  \
       
   109     "signed = (boolean) false"           \
       
   110     "; "                                 \
       
   111     "audio/x-raw-float, "                \
       
   112     "rate = (int) [ 1, MAX ], "          \
       
   113     "channels = (int) [ 1, 2 ], "        \
       
   114     "endianness = (int) LITTLE_ENDIAN, " \
       
   115     "width = (int) { 32, 64 }; "         \
       
   116     "audio/x-alaw, "                     \
       
   117     "rate = (int) [ 8000, 192000 ], "    \
       
   118     "channels = (int) [ 1, 2 ], "        \
       
   119     "width = (int) 8, "                  \
       
   120     "depth = (int) 8, "                  \
       
   121     "signed = (boolean) false; "         \
       
   122     "audio/x-mulaw, "                    \
       
   123     "rate = (int) [ 8000, 192000 ], "    \
       
   124     "channels = (int) [ 1, 2 ], "        \
       
   125     "width = (int) 8, "                  \
       
   126     "depth = (int) 8, "                  \
    99     "signed = (boolean) false"
   127     "signed = (boolean) false"
   100 
   128 
   101 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
   129 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
   102     GST_PAD_SINK,
   130     GST_PAD_SINK,
   103     GST_PAD_ALWAYS,
   131     GST_PAD_ALWAYS,
   108     GST_PAD_SRC,
   136     GST_PAD_SRC,
   109     GST_PAD_ALWAYS,
   137     GST_PAD_ALWAYS,
   110     GST_STATIC_CAPS ("audio/x-wav")
   138     GST_STATIC_CAPS ("audio/x-wav")
   111     );
   139     );
   112 
   140 
   113 #ifndef __SYMBIAN32__  //rj
       
   114 GST_BOILERPLATE (GstWavEnc, gst_wavenc, GstElement, GST_TYPE_ELEMENT);
   141 GST_BOILERPLATE (GstWavEnc, gst_wavenc, GstElement, GST_TYPE_ELEMENT);
   115 #endif
       
   116 
       
   117 //rj
       
   118 static void gst_wavenc_base_init (gpointer g_class);
       
   119 static void gst_wavenc_class_init (GstWavEncClass * klass);
       
   120 static void gst_wavenc_init (GstWavEnc * wavenc, GstWavEncClass * klass);
       
   121 static GstElementClass *parent_class = NULL;
       
   122 //rj
       
   123 
   142 
   124 static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstBuffer * buf);
   143 static GstFlowReturn gst_wavenc_chain (GstPad * pad, GstBuffer * buf);
   125 static gboolean gst_wavenc_event (GstPad * pad, GstEvent * event);
   144 static gboolean gst_wavenc_event (GstPad * pad, GstEvent * event);
   126 static GstStateChangeReturn gst_wavenc_change_state (GstElement * element,
   145 static GstStateChangeReturn gst_wavenc_change_state (GstElement * element,
   127     GstStateChange transition);
   146     GstStateChange transition);
   128 static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps);
   147 static gboolean gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps);
   129 
   148 
   130 
       
   131 
       
   132 
       
   133 GType gst_wavenc_get_type (void)
       
   134 {
       
   135   static GType wavenc_type = 0;
       
   136 
       
   137   if (!wavenc_type) {
       
   138     static const GTypeInfo wavenc_info = {
       
   139       sizeof (GstWavEncClass),
       
   140       gst_wavenc_base_init,
       
   141       NULL,
       
   142       (GClassInitFunc) gst_wavenc_class_init,
       
   143       NULL,
       
   144       NULL,
       
   145       sizeof (GstWavEnc),
       
   146       0,
       
   147       (GInstanceInitFunc) gst_wavenc_init,
       
   148     };
       
   149 
       
   150     wavenc_type =
       
   151         g_type_register_static (GST_TYPE_ELEMENT, "GstWavEnc",
       
   152         &wavenc_info, 0);
       
   153   }
       
   154   return wavenc_type;
       
   155 }
       
   156 
       
   157 
       
   158 static void
   149 static void
   159 gst_wavenc_base_init (gpointer g_class)
   150 gst_wavenc_base_init (gpointer g_class)
   160 {
   151 {
   161   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
   152   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
   162 
   153 
   174 gst_wavenc_class_init (GstWavEncClass * klass)
   165 gst_wavenc_class_init (GstWavEncClass * klass)
   175 {
   166 {
   176   GstElementClass *element_class;
   167   GstElementClass *element_class;
   177 
   168 
   178   element_class = (GstElementClass *) klass;
   169   element_class = (GstElementClass *) klass;
   179   
       
   180   parent_class = g_type_class_peek_parent (klass);//rj
       
   181 
   170 
   182   element_class->change_state = GST_DEBUG_FUNCPTR (gst_wavenc_change_state);
   171   element_class->change_state = GST_DEBUG_FUNCPTR (gst_wavenc_change_state);
   183 }
   172 }
   184 
   173 
   185 static void
   174 static void
   201   gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->srcpad);
   190   gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->srcpad);
   202 }
   191 }
   203 
   192 
   204 #define WAV_HEADER_LEN 44
   193 #define WAV_HEADER_LEN 44
   205 
   194 
   206 /* FIXME: we are probably not handling depth != width correctly here */
       
   207 static GstBuffer *
   195 static GstBuffer *
   208 gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
   196 gst_wavenc_create_header_buf (GstWavEnc * wavenc, guint audio_data_size)
   209 {
   197 {
   210   struct wave_header wave;
   198   struct wave_header wave;
   211   GstBuffer *buf;
   199   GstBuffer *buf;
   214   buf = gst_buffer_new_and_alloc (WAV_HEADER_LEN);
   202   buf = gst_buffer_new_and_alloc (WAV_HEADER_LEN);
   215   header = GST_BUFFER_DATA (buf);
   203   header = GST_BUFFER_DATA (buf);
   216   memset (header, 0, WAV_HEADER_LEN);
   204   memset (header, 0, WAV_HEADER_LEN);
   217 
   205 
   218   wave.common.wChannels = wavenc->channels;
   206   wave.common.wChannels = wavenc->channels;
   219   wave.common.wBitsPerSample = wavenc->depth;
   207   wave.common.wBitsPerSample = wavenc->width;
   220   wave.common.dwSamplesPerSec = wavenc->rate;
   208   wave.common.dwSamplesPerSec = wavenc->rate;
   221 
   209 
   222   /* Fill out our wav-header with some information */
   210   /* Fill out our wav-header with some information */
   223   memcpy (wave.riff.id, "RIFF", 4);
   211   memcpy (wave.riff.id, "RIFF", 4);
       
   212   //g_printf("before wave.riff.len %d \n" ,wave.riff.len);
   224   wave.riff.len = audio_data_size + WAV_HEADER_LEN - 8;
   213   wave.riff.len = audio_data_size + WAV_HEADER_LEN - 8;
       
   214   //g_printf("after wave.riff.len %d \n" ,wave.riff.len);
   225   memcpy (wave.riff.wav_id, "WAVE", 4);
   215   memcpy (wave.riff.wav_id, "WAVE", 4);
   226 
   216 
   227   memcpy (wave.format.id, "fmt ", 4);
   217   memcpy (wave.format.id, "fmt ", 4);
   228   wave.format.len = 16;
   218   wave.format.len = 16;
   229 
   219 
   230   wave.common.wFormatTag = WAVE_FORMAT_PCM;
   220   wave.common.wFormatTag = wavenc->format;
       
   221   wave.common.wBlockAlign = (wavenc->width / 8) * wave.common.wChannels;
   231   wave.common.dwAvgBytesPerSec =
   222   wave.common.dwAvgBytesPerSec =
   232       wave.common.wChannels * wave.common.dwSamplesPerSec *
   223       wave.common.wBlockAlign * wave.common.dwSamplesPerSec;
   233       (wave.common.wBitsPerSample >> 3);
       
   234   wave.common.wBlockAlign =
       
   235       wave.common.wChannels * (wave.common.wBitsPerSample >> 3);
       
   236 
   224 
   237   memcpy (wave.data.id, "data", 4);
   225   memcpy (wave.data.id, "data", 4);
   238   wave.data.len = audio_data_size;
   226   wave.data.len = audio_data_size;
   239 
   227 
   240   memcpy (header, (char *) wave.riff.id, 4);
   228   memcpy (header, (char *) wave.riff.id, 4);
   285 static gboolean
   273 static gboolean
   286 gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps)
   274 gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps)
   287 {
   275 {
   288   GstWavEnc *wavenc;
   276   GstWavEnc *wavenc;
   289   GstStructure *structure;
   277   GstStructure *structure;
   290   gint chans, rate, width, depth;
   278   const gchar *name;
       
   279   gint chans, rate, width;
   291 
   280 
   292   wavenc = GST_WAVENC (gst_pad_get_parent (pad));
   281   wavenc = GST_WAVENC (gst_pad_get_parent (pad));
   293 
   282 
   294   if (wavenc->sent_header) {
   283   if (wavenc->sent_header) {
   295     GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream");
   284     GST_WARNING_OBJECT (wavenc, "cannot change format in middle of stream");
   297   }
   286   }
   298 
   287 
   299   GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps);
   288   GST_DEBUG_OBJECT (wavenc, "got caps: %" GST_PTR_FORMAT, caps);
   300 
   289 
   301   structure = gst_caps_get_structure (caps, 0);
   290   structure = gst_caps_get_structure (caps, 0);
       
   291   name = gst_structure_get_name (structure);
       
   292 
   302   if (!gst_structure_get_int (structure, "channels", &chans) ||
   293   if (!gst_structure_get_int (structure, "channels", &chans) ||
   303       !gst_structure_get_int (structure, "rate", &rate) ||
   294       !gst_structure_get_int (structure, "rate", &rate)) {
   304       !gst_structure_get_int (structure, "width", &width) ||
       
   305       (width != 8 && !gst_structure_get_int (structure, "depth", &depth))) {
       
   306     GST_WARNING_OBJECT (wavenc, "caps incomplete");
   295     GST_WARNING_OBJECT (wavenc, "caps incomplete");
   307     goto fail;
   296     goto fail;
   308   }
   297   }
   309 
   298 
       
   299   if (strcmp (name, "audio/x-raw-int") == 0) {
       
   300     if (!gst_structure_get_int (structure, "width", &width)) {
       
   301       GST_WARNING_OBJECT (wavenc, "caps incomplete");
       
   302       goto fail;
       
   303     }
       
   304     wavenc->format = GST_RIFF_WAVE_FORMAT_PCM;
       
   305     wavenc->width = width;
       
   306   } else if (strcmp (name, "audio/x-raw-float") == 0) {
       
   307     if (!gst_structure_get_int (structure, "width", &width)) {
       
   308       GST_WARNING_OBJECT (wavenc, "caps incomplete");
       
   309       goto fail;
       
   310     }
       
   311     wavenc->format = GST_RIFF_WAVE_FORMAT_FLOAT;
       
   312     wavenc->width = width;
       
   313   } else if (strcmp (name, "audio/x-alaw") == 0) {
       
   314     wavenc->format = GST_RIFF_WAVE_FORMAT_ALAW;
       
   315     wavenc->width = 8;
       
   316   } else if (strcmp (name, "audio/x-mulaw") == 0) {
       
   317     wavenc->format = GST_RIFF_WAVE_FORMAT_MULAW;
       
   318     wavenc->width = 8;
       
   319   } else {
       
   320     GST_WARNING_OBJECT (wavenc, "Unsupported format %s", name);
       
   321     goto fail;
       
   322   }
       
   323 
   310   wavenc->channels = chans;
   324   wavenc->channels = chans;
   311   wavenc->width = width;
       
   312   wavenc->depth = (width == 8) ? 8 : depth;
       
   313   wavenc->rate = rate;
   325   wavenc->rate = rate;
   314 
   326 
   315   GST_LOG_OBJECT (wavenc, "accepted caps: chans=%u width=%u depth=%u rate=%u",
   327   GST_LOG_OBJECT (wavenc,
   316       wavenc->channels, wavenc->width, wavenc->depth, wavenc->rate);
   328       "accepted caps: format=0x%04x chans=%u width=%u rate=%u",
       
   329       wavenc->format, wavenc->channels, wavenc->width, wavenc->rate);
   317 
   330 
   318   gst_object_unref (wavenc);
   331   gst_object_unref (wavenc);
   319   return TRUE;
   332   return TRUE;
   320 
   333 
   321 fail:
   334 fail:
   623       }
   636       }
   624 #endif
   637 #endif
   625       /* write header with correct length values */
   638       /* write header with correct length values */
   626       gst_wavenc_push_header (wavenc, wavenc->length);
   639       gst_wavenc_push_header (wavenc, wavenc->length);
   627 
   640 
       
   641       /* we're done with this file */
       
   642       wavenc->finished_properly = TRUE;
       
   643 
   628       /* and forward the EOS event */
   644       /* and forward the EOS event */
   629       res = gst_pad_event_default (pad, event);
   645       res = gst_pad_event_default (pad, event);
   630       break;
   646       break;
   631     }
   647     }
   632     case GST_EVENT_NEWSEGMENT:
   648     case GST_EVENT_NEWSEGMENT:
   654   if (!wavenc->sent_header) {
   670   if (!wavenc->sent_header) {
   655     /* use bogus size initially, we'll write the real
   671     /* use bogus size initially, we'll write the real
   656      * header when we get EOS and know the exact length */
   672      * header when we get EOS and know the exact length */
   657     flow = gst_wavenc_push_header (wavenc, 0x7FFF0000);
   673     flow = gst_wavenc_push_header (wavenc, 0x7FFF0000);
   658 
   674 
       
   675     /* starting a file, means we have to finish it properly */
       
   676     wavenc->finished_properly = FALSE;
       
   677 
   659     if (flow != GST_FLOW_OK)
   678     if (flow != GST_FLOW_OK)
   660       return flow;
   679       return flow;
   661 
   680 
   662     GST_DEBUG_OBJECT (wavenc, "wrote dummy header");
   681     GST_DEBUG_OBJECT (wavenc, "wrote dummy header");
   663     wavenc->sent_header = TRUE;
   682     wavenc->sent_header = TRUE;
   664   }
   683   }
   665 
       
   666   wavenc->length += GST_BUFFER_SIZE (buf);
       
   667 
   684 
   668   GST_LOG_OBJECT (wavenc, "pushing %u bytes raw audio, ts=%" GST_TIME_FORMAT,
   685   GST_LOG_OBJECT (wavenc, "pushing %u bytes raw audio, ts=%" GST_TIME_FORMAT,
   669       GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
   686       GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
   670 
   687 
   671   buf = gst_buffer_make_metadata_writable (buf);
   688   buf = gst_buffer_make_metadata_writable (buf);
   672   gst_buffer_set_caps (buf, GST_PAD_CAPS (wavenc->srcpad));
   689   gst_buffer_set_caps (buf, GST_PAD_CAPS (wavenc->srcpad));
   673   GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->length;
   690   GST_BUFFER_OFFSET (buf) = WAV_HEADER_LEN + wavenc->length;
   674   GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
   691   GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
   675 
   692 
       
   693   wavenc->length += GST_BUFFER_SIZE (buf);
       
   694 
   676   flow = gst_pad_push (wavenc->srcpad, buf);
   695   flow = gst_pad_push (wavenc->srcpad, buf);
   677 
   696 
   678   return flow;
   697   return flow;
   679 }
   698 }
   680 
   699 
   684   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
   703   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
   685   GstWavEnc *wavenc = GST_WAVENC (element);
   704   GstWavEnc *wavenc = GST_WAVENC (element);
   686 
   705 
   687   switch (transition) {
   706   switch (transition) {
   688     case GST_STATE_CHANGE_NULL_TO_READY:
   707     case GST_STATE_CHANGE_NULL_TO_READY:
       
   708       wavenc->format = 0;
   689       wavenc->channels = 0;
   709       wavenc->channels = 0;
   690       wavenc->width = 0;
   710       wavenc->width = 0;
   691       wavenc->depth = 0;
       
   692       wavenc->rate = 0;
   711       wavenc->rate = 0;
   693       wavenc->length = 0;
   712       wavenc->length = 0;
   694       wavenc->sent_header = FALSE;
   713       wavenc->sent_header = FALSE;
       
   714       /* its true because we haven't writen anything */
       
   715       wavenc->finished_properly = TRUE;
   695       break;
   716       break;
   696     default:
   717     default:
   697       break;
   718       break;
   698   }
   719   }
   699 
   720 
   700   ret = parent_class->change_state (element, transition);
   721   ret = parent_class->change_state (element, transition);
   701   if (ret != GST_STATE_CHANGE_SUCCESS)
   722   if (ret != GST_STATE_CHANGE_SUCCESS)
   702     return ret;
   723     return ret;
   703 
   724 
       
   725   switch (transition) {
       
   726     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   727       if (!wavenc->finished_properly) {
       
   728         GST_ELEMENT_WARNING (wavenc, STREAM, MUX,
       
   729             ("Wav stream not finished properly"),
       
   730             ("Wav stream not finished properly, no EOS received "
       
   731                 "before shutdown"));
       
   732       }
       
   733       break;
       
   734     default:
       
   735       break;
       
   736   }
       
   737 
   704   return ret;
   738   return ret;
   705 }
   739 }
   706 
   740 
   707 static gboolean
   741 static gboolean
   708 plugin_init (GstPlugin * plugin)
   742 plugin_init (GstPlugin * plugin)
   709 {
   743 {
   710   return gst_element_register (plugin, "wavenc", GST_RANK_NONE,
   744   return gst_element_register (plugin, "wavenc", GST_RANK_PRIMARY,
   711       GST_TYPE_WAVENC);
   745       GST_TYPE_WAVENC);
   712 }
   746 }
   713 
   747 
   714 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
   748 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
   715     GST_VERSION_MINOR,
   749     GST_VERSION_MINOR,