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