Tizen 2.1 base
[profile/ivi/gst-ffmpeg0.10.git] / ext / ffmpeg / gstffmpegmux.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * * Modifications by Samsung Electronics Co., Ltd.
21  * 1. Add new function to get expected trailer size
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <string.h>
29 #ifdef HAVE_FFMPEG_UNINSTALLED
30 #include <avformat.h>
31 #else
32 #include <libavformat/avformat.h>
33 #endif
34
35 #include <gst/gst.h>
36 #include <gst/base/gstcollectpads.h>
37
38 #include "gstffmpeg.h"
39 #include "gstffmpegcodecmap.h"
40 #include "gstffmpegutils.h"
41
42 #ifndef GST_EXT_FFMUX_ENHANCEMENT
43 #define GST_EXT_FFMUX_ENHANCEMENT
44 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
45
46 typedef struct _GstFFMpegMux GstFFMpegMux;
47 typedef struct _GstFFMpegMuxPad GstFFMpegMuxPad;
48
49 struct _GstFFMpegMuxPad
50 {
51   GstCollectData collect;       /* we extend the CollectData */
52
53   gint padnum;
54 };
55
56 struct _GstFFMpegMux
57 {
58   GstElement element;
59
60   GstCollectPads *collect;
61   /* We need to keep track of our pads, so we do so here. */
62   GstPad *srcpad;
63
64   AVFormatContext *context;
65   gboolean opened;
66
67   gint videopads, audiopads;
68 #ifdef GST_EXT_FFMUX_ENHANCEMENT
69   guint expected_trailer_size, nb_video_frames, nb_audio_frames;
70 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
71
72   /*< private > */
73   /* event_function is the collectpads default eventfunction */
74   GstPadEventFunction event_function;
75   int preload;
76   int max_delay;
77 };
78
79 typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
80
81 struct _GstFFMpegMuxClass
82 {
83   GstElementClass parent_class;
84
85   AVOutputFormat *in_plugin;
86 };
87
88 #define GST_TYPE_FFMPEGMUX \
89   (gst_ffmpegdec_get_type())
90 #define GST_FFMPEGMUX(obj) \
91   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGMUX,GstFFMpegMux))
92 #define GST_FFMPEGMUX_CLASS(klass) \
93   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGMUX,GstFFMpegMuxClass))
94 #define GST_IS_FFMPEGMUX(obj) \
95   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGMUX))
96 #define GST_IS_FFMPEGMUX_CLASS(klass) \
97   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGMUX))
98
99 enum
100 {
101   /* FILL ME */
102   LAST_SIGNAL
103 };
104
105 enum
106 {
107   ARG_0,
108   /* FILL ME */
109 };
110
111 enum
112 {
113   PROP_0,
114   PROP_PRELOAD,
115   PROP_MAXDELAY,
116 #ifdef GST_EXT_FFMUX_ENHANCEMENT
117   PROP_EXPECTED_TRAILER_SIZE,
118   PROP_NUMBER_VIDEO_FRAMES,
119   PROP_NUMBER_AUDIO_FRAMES,
120 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
121 };
122
123 /* A number of function prototypes are given so we can refer to them later. */
124 static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass);
125 static void gst_ffmpegmux_base_init (gpointer g_class);
126 static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux,
127     GstFFMpegMuxClass * g_class);
128 static void gst_ffmpegmux_finalize (GObject * object);
129
130 static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps);
131 static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
132     GstPadTemplate * templ, const gchar * name);
133 static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads,
134     gpointer user_data);
135
136 static gboolean gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event);
137
138 static GstStateChangeReturn gst_ffmpegmux_change_state (GstElement * element,
139     GstStateChange transition);
140
141 static void gst_ffmpegmux_set_property (GObject * object, guint prop_id,
142     const GValue * value, GParamSpec * pspec);
143 static void gst_ffmpegmux_get_property (GObject * object, guint prop_id,
144     GValue * value, GParamSpec * pspec);
145
146 static GstCaps *gst_ffmpegmux_get_id_caps (enum CodecID *id_list);
147 static void gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps,
148     const gchar * field, guint num, const gint * values);
149
150 #define GST_FFMUX_PARAMS_QDATA g_quark_from_static_string("ffmux-params")
151
152 #ifdef GST_EXT_FFMUX_ENHANCEMENT 
153 static void gst_ffmpegmux_release_pad (GstElement * element, GstPad * pad);
154 #endif
155
156 static GstElementClass *parent_class = NULL;
157
158 /*static guint gst_ffmpegmux_signals[LAST_SIGNAL] = { 0 }; */
159
160 typedef struct
161 {
162   const char *name;
163   const char *replacement;
164 } GstFFMpegMuxReplacement;
165
166 static const char *
167 gst_ffmpegmux_get_replacement (const char *name)
168 {
169   static const GstFFMpegMuxReplacement blacklist[] = {
170     {"avi", "avimux"},
171     {"matroska", "matroskamux"},
172     {"mov", "qtmux"},
173     {"mpegts", "mpegtsmux"},
174     {"mp4", "mp4mux"},
175     {"mpjpeg", "multipartmux"},
176     {"ogg", "oggmux"},
177     {"wav", "wavenc"},
178     {"webm", "webmmux"},
179     {"mxf", "mxfmux"},
180     {"3gp", "gppmux"},
181     {"yuv4mpegpipe", "y4menc"},
182     {"aiff", "aiffmux"},
183     {"adts", "aacparse"},
184     {"asf", "asfmux"},
185     {"asf_stream", "asfmux"},
186     {"flv", "flvmux"},
187     {"mp3", "id3v2mux"},
188     {"mp2", "id3v2mux"}
189   };
190   int i;
191
192   for (i = 0; i < sizeof (blacklist) / sizeof (blacklist[0]); i++) {
193     if (strcmp (blacklist[i].name, name) == 0) {
194       return blacklist[i].replacement;
195     }
196   }
197
198   return NULL;
199 }
200
201 static gboolean
202 gst_ffmpegmux_is_formatter (const char *name)
203 {
204   static const char *replace[] = {
205     "mp2", "mp3", NULL
206   };
207   int i;
208
209   for (i = 0; replace[i]; i++)
210     if (strcmp (replace[i], name) == 0)
211       return TRUE;
212   return FALSE;
213 }
214
215 #ifdef GST_EXT_FFMUX_ENHANCEMENT
216
217 /* trailer entry size */
218 #define ENTRY_SIZE_VIDEO_STTS   8
219 #define ENTRY_SIZE_VIDEO_STSS   4
220 #define ENTRY_SIZE_VIDEO_STSZ   4
221 #define ENTRY_SIZE_VIDEO_STCO   4
222 #define ENTRY_SIZE_AUDIO_STSZ   4
223 #define ENTRY_SIZE_AUDIO_STCO   4
224
225 /* ffmux_adts */
226 #define MUX_ADTS_NAME           "adts"
227 #define MUX_ADTS_SIZE_HEADER    8
228 #define MUX_ADTS_SIZE_ENTRY     7
229
230 /* others */
231 #define MUX_OTHERS_SIZE_DEFAULT         248     /* ftyp + free + moov + mvhd + udta */
232 #define MUX_OTHERS_SIZE_HEADER_AMR      (MUX_OTHERS_SIZE_DEFAULT + 410)
233 #define MUX_OTHERS_SIZE_HEADER_AAC      (MUX_OTHERS_SIZE_DEFAULT + 432)
234
235
236 static void update_expected_trailer_size(GstFFMpegMux *ffmpegmux)
237 {
238         int i = 0;
239         guint nb_video_frames = 0;
240         guint nb_video_i_frames = 0;
241         guint nb_stts_entry = 0;
242         guint nb_audio_frames = 0;
243         gboolean video_stream = FALSE;
244         gboolean audio_stream = FALSE;
245         guint exp_size = 0;
246         AVCodecContext *codec_context = NULL;
247         enum CodecID video_codec_id;
248         enum CodecID audio_codec_id;
249
250         if (ffmpegmux == NULL) {
251                 GST_WARNING("ffmpegmux is NULL");
252                 return;
253         }
254
255         for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
256                 codec_context = ffmpegmux->context->streams[i]->codec;
257                 if (codec_context->codec_type == CODEC_TYPE_VIDEO) {
258                         nb_video_frames += codec_context->frame_number;
259                         nb_video_i_frames += codec_context->i_frame_number;
260                         nb_stts_entry += codec_context->stts_count;
261
262                         video_stream = TRUE;
263                         video_codec_id = codec_context->codec_id;
264                 } else if (codec_context->codec_type == CODEC_TYPE_AUDIO) {
265                         nb_audio_frames += codec_context->frame_number;
266
267                         audio_stream = TRUE;
268                         audio_codec_id = codec_context->codec_id;
269                 }
270         }
271
272         /*
273         [[ Metadata Size ]]
274         - COMMON
275         ftyp = 32(H.264 video included) or 28(H.263 video included or audio only)
276         free = 8
277         moov = 8
278           mvhd = 108
279           udta = 96(meta in case of audio only) or
280                  84(loci in case of video only or video/audio)
281
282         - VIDEO:H.264 = 487(or 489) + (8*stts_count) + (8*frame) + (4*I-frame)
283           trak = 8
284             tkhd = 92
285             mdia = 8
286               mdhd = 32
287               hdir = 45
288               minf = 8
289                 vmhd = 20
290                 dinf = 36
291                 stbl = 8
292                   stsd = 134 (SPS 9, PPS 4) or 136 (SPS 111, PPS 4)
293                   stts = 16 + (8*stts_count)
294                   stss = 16 + (4*I-frame)
295                   stsc = 28
296                   stsz = 20 + (4*frame)
297                   stco = 16 + (4*frame)
298
299         - VIDEO:H.263 = 470 + + (8*stts_count) + (8*frame) + (4*I-frame)
300           trak = 8
301             tkhd = 92
302             mdia = 8
303               mdhd = 32
304               hdir = 45
305               minf = 8
306                 vmhd = 20
307                 dinf = 36
308                 stbl = 8
309                   stsd = 117 -> different from H.264
310                   stts = 16 + (8*stts_count)
311                   stss = 16 + (4*I-frame)
312                   stsc = 28
313                   stsz = 20 + (4*frame)
314                   stco = 16 + (4*frame)
315
316         - AUDIO:AAC = 432 + (8*audio_frame)
317           trak = 8
318             tkhd = 92
319             mdia = 8
320               mdhd = 32
321               hdir = 45
322               minf = 8
323                 smhd = 16
324                 dinf = 36
325                 stbl = 8
326                   stsd = 91
327                   stts = 24
328                   stsc = 28
329                   stsz = 20 + (4*frame)
330                   stco = 16 + (4*frame)
331
332         - AUDIO:AMR = 410 + (4*audio_frame)
333           trak = 8
334             tkhd = 92
335             mdia = 8
336               mdhd = 32
337               hdir = 45
338               minf = 8
339                 smhd = 16
340                 dinf = 36
341                 stbl = 8
342                   stsd = 69 -> different from AAC
343                   stts = 24
344                   stsc = 28
345                   stsz = 20 -> different from AAC
346                   stco = 16 + (4*frame)
347         */
348
349         /* Calculate trailer size for video stream */
350         if (video_stream) {
351                 /* ftyp + free + moov + mvhd + udta : H.264 -> 240, H.263 -> 236 */
352                 /* trak size except frame related   : H.264 -> 489, H.263 -> 470 */
353                 if (video_codec_id == CODEC_ID_H263 ) {
354                         exp_size = 236 + 470;
355                 } else {
356                         exp_size = 240 + 489;
357                 }
358
359                 /* frame related */
360                 exp_size += (ENTRY_SIZE_VIDEO_STTS * nb_stts_entry) + \
361                             (ENTRY_SIZE_VIDEO_STSS * nb_video_i_frames) + \
362                             ((ENTRY_SIZE_VIDEO_STSZ + ENTRY_SIZE_VIDEO_STCO) * nb_video_frames);
363        }
364
365        if (audio_stream) {
366                 /* Calculate trailer size for audio stream */
367                 if (!strcmp(ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
368                         /* ffmux_adts */
369                        exp_size += MUX_ADTS_SIZE_HEADER + (MUX_ADTS_SIZE_ENTRY * nb_audio_frames);
370                 }  else {
371                         /* others - ffmux_3gp/mp4/amr */
372                         if (audio_codec_id == CODEC_ID_AMR_NB) {
373                                 /* AMR_NB codec */
374                                exp_size += MUX_OTHERS_SIZE_HEADER_AMR + (ENTRY_SIZE_AUDIO_STCO * nb_audio_frames);
375                         } else {
376                                 /* AAC codec */
377                                exp_size += MUX_OTHERS_SIZE_HEADER_AAC + ((ENTRY_SIZE_AUDIO_STSZ + ENTRY_SIZE_AUDIO_STCO) * nb_audio_frames);
378                         }
379                 }
380         }
381
382         ffmpegmux->expected_trailer_size = exp_size;
383         ffmpegmux->nb_video_frames = nb_video_frames;
384         ffmpegmux->nb_audio_frames = nb_audio_frames;
385
386         return;
387 }
388 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
389
390 static void
391 gst_ffmpegmux_base_init (gpointer g_class)
392 {
393   GstFFMpegMuxClass *klass = (GstFFMpegMuxClass *) g_class;
394   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
395   GstPadTemplate *videosinktempl, *audiosinktempl, *srctempl;
396   AVOutputFormat *in_plugin;
397   GstCaps *srccaps, *audiosinkcaps, *videosinkcaps;
398   enum CodecID *video_ids = NULL, *audio_ids = NULL;
399   gchar *longname, *description;
400   const char *replacement;
401   gboolean is_formatter;
402
403   in_plugin =
404       (AVOutputFormat *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
405       GST_FFMUX_PARAMS_QDATA);
406   g_assert (in_plugin != NULL);
407
408   /* construct the element details struct */
409   replacement = gst_ffmpegmux_get_replacement (in_plugin->name);
410   is_formatter = gst_ffmpegmux_is_formatter (in_plugin->name);
411   if (replacement != NULL) {
412     longname =
413         g_strdup_printf ("FFmpeg %s %s (not recommended, use %s instead)",
414         in_plugin->long_name, is_formatter ? "formatter" : "muxer",
415         replacement);
416     description =
417         g_strdup_printf ("FFmpeg %s %s (not recommended, use %s instead)",
418         in_plugin->long_name, is_formatter ? "formatter" : "muxer",
419         replacement);
420   } else {
421     longname = g_strdup_printf ("FFmpeg %s %s", in_plugin->long_name,
422         is_formatter ? "formatter" : "muxer");
423     description = g_strdup_printf ("FFmpeg %s %s", in_plugin->long_name,
424         is_formatter ? "formatter" : "muxer");
425   }
426   gst_element_class_set_details_simple (element_class, longname,
427       is_formatter ? "Formatter/Metadata" : "Codec/Muxer", description,
428       "Wim Taymans <wim.taymans@chello.be>, "
429       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
430   g_free (longname);
431   g_free (description);
432
433   /* Try to find the caps that belongs here */
434   srccaps = gst_ffmpeg_formatid_to_caps (in_plugin->name);
435   if (!srccaps) {
436     GST_DEBUG ("Couldn't get source caps for muxer '%s', skipping format",
437         in_plugin->name);
438     goto beach;
439   }
440
441   if (!gst_ffmpeg_formatid_get_codecids (in_plugin->name,
442           &video_ids, &audio_ids, in_plugin)) {
443     gst_caps_unref (srccaps);
444     GST_DEBUG
445         ("Couldn't get sink caps for muxer '%s'. Most likely because no input format mapping exists.",
446         in_plugin->name);
447     goto beach;
448   }
449
450   videosinkcaps = video_ids ? gst_ffmpegmux_get_id_caps (video_ids) : NULL;
451   audiosinkcaps = audio_ids ? gst_ffmpegmux_get_id_caps (audio_ids) : NULL;
452
453   /* fix up allowed caps for some muxers */
454   /* FIXME : This should be in gstffmpegcodecmap.c ! */
455   if (strcmp (in_plugin->name, "flv") == 0) {
456     const gint rates[] = { 44100, 22050, 11025 };
457
458     gst_ffmpeg_mux_simple_caps_set_int_list (audiosinkcaps, "rate", 3, rates);
459   } else if (strcmp (in_plugin->name, "gif") == 0) {
460     if (videosinkcaps)
461       gst_caps_unref (videosinkcaps);
462
463     videosinkcaps =
464         gst_caps_from_string ("video/x-raw-rgb, bpp=(int)24, depth=(int)24");
465   }
466
467   /* pad templates */
468   srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
469   gst_element_class_add_pad_template (element_class, srctempl);
470
471   if (audiosinkcaps) {
472     audiosinktempl = gst_pad_template_new ("audio_%d",
473         GST_PAD_SINK, GST_PAD_REQUEST, audiosinkcaps);
474     gst_element_class_add_pad_template (element_class, audiosinktempl);
475   }
476
477   if (videosinkcaps) {
478     videosinktempl = gst_pad_template_new ("video_%d",
479         GST_PAD_SINK, GST_PAD_REQUEST, videosinkcaps);
480     gst_element_class_add_pad_template (element_class, videosinktempl);
481   }
482
483 beach:
484   klass->in_plugin = in_plugin;
485 }
486
487 static void
488 gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
489 {
490   GObjectClass *gobject_class;
491   GstElementClass *gstelement_class;
492
493   gobject_class = (GObjectClass *) klass;
494   gstelement_class = (GstElementClass *) klass;
495
496   parent_class = g_type_class_peek_parent (klass);
497
498   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_set_property);
499   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_get_property);
500
501   g_object_class_install_property (gobject_class, PROP_PRELOAD,
502       g_param_spec_int ("preload", "preload",
503           "Set the initial demux-decode delay (in microseconds)", 0, G_MAXINT,
504           0, G_PARAM_READWRITE));
505
506   g_object_class_install_property (gobject_class, PROP_MAXDELAY,
507       g_param_spec_int ("maxdelay", "maxdelay",
508           "Set the maximum demux-decode delay (in microseconds)", 0, G_MAXINT,
509           0, G_PARAM_READWRITE));
510
511   gstelement_class->request_new_pad = gst_ffmpegmux_request_new_pad;
512   gstelement_class->change_state = gst_ffmpegmux_change_state;
513   gobject_class->finalize = gst_ffmpegmux_finalize;
514
515 #ifdef GST_EXT_FFMUX_ENHANCEMENT
516   gstelement_class->release_pad = gst_ffmpegmux_release_pad;
517
518   /* properties */
519   g_object_class_install_property (gobject_class, PROP_EXPECTED_TRAILER_SIZE,
520       g_param_spec_uint ("expected-trailer-size", "Expected Trailer Size",
521           "Expected trailer size (bytes)",
522           0, G_MAXUINT, 0, G_PARAM_READABLE));
523   g_object_class_install_property (gobject_class, PROP_NUMBER_VIDEO_FRAMES,
524       g_param_spec_uint ("number-video-frames", "Number of video frames",
525           "Current number of video frames",
526           0, G_MAXUINT, 0, G_PARAM_READABLE));
527   g_object_class_install_property (gobject_class, PROP_NUMBER_AUDIO_FRAMES,
528       g_param_spec_uint ("number-audio-frames", "Number of audio frames",
529           "Current number of audio frames",
530           0, G_MAXUINT, 0, G_PARAM_READABLE));
531 #endif
532 }
533
534 static void
535 gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux, GstFFMpegMuxClass * g_class)
536 {
537   GstElementClass *klass = GST_ELEMENT_CLASS (g_class);
538   GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass *) klass;
539   GstPadTemplate *templ = gst_element_class_get_pad_template (klass, "src");
540
541   ffmpegmux->srcpad = gst_pad_new_from_template (templ, "src");
542   gst_pad_set_caps (ffmpegmux->srcpad, gst_pad_template_get_caps (templ));
543   gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->srcpad);
544
545   ffmpegmux->collect = gst_collect_pads_new ();
546   gst_collect_pads_set_function (ffmpegmux->collect,
547       (GstCollectPadsFunction) gst_ffmpegmux_collected, ffmpegmux);
548
549   ffmpegmux->context = g_new0 (AVFormatContext, 1);
550   ffmpegmux->context->oformat = oclass->in_plugin;
551   ffmpegmux->context->nb_streams = 0;
552   g_snprintf (ffmpegmux->context->filename,
553       sizeof (ffmpegmux->context->filename),
554       "gstreamer://%p", ffmpegmux->srcpad);
555   ffmpegmux->opened = FALSE;
556
557   ffmpegmux->videopads = 0;
558   ffmpegmux->audiopads = 0;
559   ffmpegmux->preload = 0;
560   ffmpegmux->max_delay = 0;
561
562 #ifdef GST_EXT_FFMUX_ENHANCEMENT
563   ffmpegmux->expected_trailer_size = 0;
564   ffmpegmux->nb_video_frames = 0;
565   ffmpegmux->nb_audio_frames = 0;
566 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
567 }
568
569 #ifdef GST_EXT_FFMUX_ENHANCEMENT
570 static void
571 gst_ffmpegmux_release_pad (GstElement * element, GstPad * pad)
572 {
573   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
574   GstFFMpegMuxPad *collect_pad;
575   AVStream *st;
576   
577   collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
578   
579   GST_DEBUG("Release requested pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));  
580   st = ffmpegmux->context->streams[collect_pad->padnum];
581   if(st)
582   {
583     if(st->codec)
584     {
585         if(st->codec->codec_type == CODEC_TYPE_VIDEO)
586         {
587           ffmpegmux->videopads--;               
588         }
589         else 
590         {
591           ffmpegmux->audiopads--;
592         }
593         g_free(st->codec);
594     }
595     ffmpegmux->context->nb_streams--;
596     g_free(st);
597  }
598   gst_collect_pads_remove_pad (ffmpegmux->collect, pad);
599   gst_element_remove_pad (element, pad);
600 }
601 #endif
602
603 static void
604 gst_ffmpegmux_set_property (GObject * object, guint prop_id,
605     const GValue * value, GParamSpec * pspec)
606 {
607   GstFFMpegMux *src;
608
609   src = (GstFFMpegMux *) object;
610
611   switch (prop_id) {
612     case PROP_PRELOAD:
613       src->preload = g_value_get_int (value);
614       break;
615     case PROP_MAXDELAY:
616       src->max_delay = g_value_get_int (value);
617       break;
618     default:
619       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
620       break;
621   }
622 }
623
624 static void
625 gst_ffmpegmux_get_property (GObject * object, guint prop_id, GValue * value,
626     GParamSpec * pspec)
627 {
628   GstFFMpegMux *src;
629
630   src = (GstFFMpegMux *) object;
631
632   switch (prop_id) {
633     case PROP_PRELOAD:
634       g_value_set_int (value, src->preload);
635       break;
636     case PROP_MAXDELAY:
637       g_value_set_int (value, src->max_delay);
638       break;
639 #ifdef GST_EXT_FFMUX_ENHANCEMENT
640     case PROP_EXPECTED_TRAILER_SIZE:
641       g_value_set_uint (value, src->expected_trailer_size);
642       break;
643     case PROP_NUMBER_VIDEO_FRAMES:
644       g_value_set_uint (value, src->nb_video_frames);
645       break;
646     case PROP_NUMBER_AUDIO_FRAMES:
647       g_value_set_uint (value, src->nb_audio_frames);
648       break;
649 #endif /* GST_EXT_FFMUX_ENHANCEMENT */
650     default:
651       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
652       break;
653   }
654 }
655
656
657 static void
658 gst_ffmpegmux_finalize (GObject * object)
659 {
660   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) object;
661
662   g_free (ffmpegmux->context);
663   gst_object_unref (ffmpegmux->collect);
664
665   if (G_OBJECT_CLASS (parent_class)->finalize)
666     G_OBJECT_CLASS (parent_class)->finalize (object);
667 }
668
669 static GstPad *
670 gst_ffmpegmux_request_new_pad (GstElement * element,
671     GstPadTemplate * templ, const gchar * name)
672 {
673   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
674   GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
675   GstFFMpegMuxPad *collect_pad;
676   gchar *padname;
677   GstPad *pad;
678   AVStream *st;
679   enum CodecType type;
680   gint bitrate = 0, framesize = 0;
681
682   g_return_val_if_fail (templ != NULL, NULL);
683   g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
684   g_return_val_if_fail (ffmpegmux->opened == FALSE, NULL);
685
686   /* figure out a name that *we* like */
687   if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
688     padname = g_strdup_printf ("video_%d", ffmpegmux->videopads++);
689     type = CODEC_TYPE_VIDEO;
690     bitrate = 64 * 1024;
691     framesize = 1152;
692   } else if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
693     padname = g_strdup_printf ("audio_%d", ffmpegmux->audiopads++);
694     type = CODEC_TYPE_AUDIO;
695     bitrate = 285 * 1024;
696   } else {
697     g_warning ("ffmux: unknown pad template!");
698     return NULL;
699   }
700
701   /* create pad */
702   pad = gst_pad_new_from_template (templ, padname);
703   collect_pad = (GstFFMpegMuxPad *)
704       gst_collect_pads_add_pad (ffmpegmux->collect, pad,
705       sizeof (GstFFMpegMuxPad));
706   collect_pad->padnum = ffmpegmux->context->nb_streams;
707
708   /* small hack to put our own event pad function and chain up to collect pad */
709   ffmpegmux->event_function = GST_PAD_EVENTFUNC (pad);
710   gst_pad_set_event_function (pad,
711       GST_DEBUG_FUNCPTR (gst_ffmpegmux_sink_event));
712
713   gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_ffmpegmux_setcaps));
714   gst_element_add_pad (element, pad);
715
716   /* AVStream needs to be created */
717   st = av_new_stream (ffmpegmux->context, collect_pad->padnum);
718   st->codec->codec_type = type;
719   st->codec->codec_id = CODEC_ID_NONE;  /* this is a check afterwards */
720   st->stream_copy = 1;          /* we're not the actual encoder */
721   st->codec->bit_rate = bitrate;
722   st->codec->frame_size = framesize;
723   /* we fill in codec during capsnego */
724
725   /* we love debug output (c) (tm) (r) */
726   GST_DEBUG ("Created %s pad for ffmux_%s element",
727       padname, ((GstFFMpegMuxClass *) klass)->in_plugin->name);
728   g_free (padname);
729
730   return pad;
731 }
732
733 /**
734  * gst_ffmpegmux_setcaps
735  * @pad: #GstPad
736  * @caps: New caps.
737  *
738  * Set caps to pad.
739  *
740  * Returns: #TRUE on success.
741  */
742 static gboolean
743 gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps)
744 {
745   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (gst_pad_get_parent (pad));
746   GstFFMpegMuxPad *collect_pad;
747   AVStream *st;
748
749   collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
750
751   st = ffmpegmux->context->streams[collect_pad->padnum];
752   ffmpegmux->context->preload = ffmpegmux->preload;
753   ffmpegmux->context->max_delay = ffmpegmux->max_delay;
754
755   /* for the format-specific guesses, we'll go to
756    * our famous codec mapper */
757   if (gst_ffmpeg_caps_to_codecid (caps, st->codec) == CODEC_ID_NONE)
758     goto not_accepted;
759
760   /* copy over the aspect ratios, ffmpeg expects the stream aspect to match the
761    * codec aspect. */
762   st->sample_aspect_ratio = st->codec->sample_aspect_ratio;
763
764 #ifdef GST_EXT_FFMUX_ENHANCEMENT
765   /* ref counting bug fix */
766   gst_object_unref(ffmpegmux);
767 #endif
768   GST_LOG_OBJECT (pad, "accepted caps %" GST_PTR_FORMAT, caps);
769   return TRUE;
770
771   /* ERRORS */
772 not_accepted:
773   {
774 #ifdef GST_EXT_FFMUX_ENHANCEMENT
775   /* ref counting bug fix */
776   gst_object_unref(ffmpegmux);
777 #endif
778     GST_LOG_OBJECT (pad, "rejecting caps %" GST_PTR_FORMAT, caps);
779     return FALSE;
780   }
781 }
782
783
784 static gboolean
785 gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event)
786 {
787   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) gst_pad_get_parent (pad);
788   gboolean res = TRUE;
789
790   switch (GST_EVENT_TYPE (event)) {
791     case GST_EVENT_TAG:{
792       GstTagList *taglist;
793       GstTagSetter *setter = GST_TAG_SETTER (ffmpegmux);
794       const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
795
796       gst_event_parse_tag (event, &taglist);
797       gst_tag_setter_merge_tags (setter, taglist, mode);
798       break;
799     }
800     default:
801       break;
802   }
803
804   /* chaining up to collectpads default event function */
805   res = ffmpegmux->event_function (pad, event);
806
807   gst_object_unref (ffmpegmux);
808   return res;
809 }
810
811 static GstFlowReturn
812 gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
813 {
814   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) user_data;
815   GSList *collected;
816   GstFFMpegMuxPad *best_pad;
817   GstClockTime best_time;
818   const GstTagList *tags;
819
820   /* open "file" (gstreamer protocol to next element) */
821   if (!ffmpegmux->opened) {
822     int open_flags = URL_WRONLY;
823
824     /* we do need all streams to have started capsnego,
825      * or things will go horribly wrong */
826     for (collected = ffmpegmux->collect->data; collected;
827         collected = g_slist_next (collected)) {
828       GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
829       AVStream *st = ffmpegmux->context->streams[collect_pad->padnum];
830
831       /* check whether the pad has successfully completed capsnego */
832       if (st->codec->codec_id == CODEC_ID_NONE) {
833         GST_ELEMENT_ERROR (ffmpegmux, CORE, NEGOTIATION, (NULL),
834             ("no caps set on stream %d (%s)", collect_pad->padnum,
835                 (st->codec->codec_type == CODEC_TYPE_VIDEO) ?
836                 "video" : "audio"));
837         return GST_FLOW_ERROR;
838       }
839       /* set framerate for audio */
840       if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
841         switch (st->codec->codec_id) {
842           case CODEC_ID_PCM_S16LE:
843           case CODEC_ID_PCM_S16BE:
844           case CODEC_ID_PCM_U16LE:
845           case CODEC_ID_PCM_U16BE:
846           case CODEC_ID_PCM_S8:
847           case CODEC_ID_PCM_U8:
848             st->codec->frame_size = 1;
849             break;
850           default:
851           {
852             GstBuffer *buffer;
853
854             /* FIXME : This doesn't work for RAW AUDIO...
855              * in fact I'm wondering if it even works for any kind of audio... */
856             buffer = gst_collect_pads_peek (ffmpegmux->collect,
857                 (GstCollectData *) collect_pad);
858             if (buffer) {
859               st->codec->frame_size =
860                   st->codec->sample_rate *
861                   GST_BUFFER_DURATION (buffer) / GST_SECOND;
862               gst_buffer_unref (buffer);
863             }
864           }
865         }
866       }
867     }
868
869     /* tags */
870     tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ffmpegmux));
871     if (tags) {
872       gint i;
873       gchar *s;
874
875       /* get the interesting ones */
876       if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) {
877         strncpy (ffmpegmux->context->title, s,
878             sizeof (ffmpegmux->context->title));
879       }
880       if (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)) {
881         strncpy (ffmpegmux->context->author, s,
882             sizeof (ffmpegmux->context->author));
883       }
884       if (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &s)) {
885         strncpy (ffmpegmux->context->copyright, s,
886             sizeof (ffmpegmux->context->copyright));
887       }
888       if (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &s)) {
889         strncpy (ffmpegmux->context->comment, s,
890             sizeof (ffmpegmux->context->comment));
891       }
892       if (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)) {
893         strncpy (ffmpegmux->context->album, s,
894             sizeof (ffmpegmux->context->album));
895       }
896       if (gst_tag_list_get_string (tags, GST_TAG_GENRE, &s)) {
897         strncpy (ffmpegmux->context->genre, s,
898             sizeof (ffmpegmux->context->genre));
899       }
900       if (gst_tag_list_get_int (tags, GST_TAG_TRACK_NUMBER, &i)) {
901         ffmpegmux->context->track = i;
902       }
903     }
904
905     /* set the streamheader flag for gstffmpegprotocol if codec supports it */
906     if (!strcmp (ffmpegmux->context->oformat->name, "flv")) {
907       open_flags |= GST_FFMPEG_URL_STREAMHEADER;
908     }
909
910     if (url_fopen (&ffmpegmux->context->pb,
911             ffmpegmux->context->filename, open_flags) < 0) {
912       GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
913           ("Failed to open stream context in ffmux"));
914       return GST_FLOW_ERROR;
915     }
916
917     if (av_set_parameters (ffmpegmux->context, NULL) < 0) {
918       GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, INIT, (NULL),
919           ("Failed to initialize muxer"));
920       return GST_FLOW_ERROR;
921     }
922
923     /* now open the mux format */
924     if (av_write_header (ffmpegmux->context) < 0) {
925       GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL),
926           ("Failed to write file header - check codec settings"));
927       return GST_FLOW_ERROR;
928     }
929
930     /* we're now opened */
931     ffmpegmux->opened = TRUE;
932
933     /* flush the header so it will be used as streamheader */
934     put_flush_packet (ffmpegmux->context->pb);
935   }
936
937   /* take the one with earliest timestamp,
938    * and push it forward */
939   best_pad = NULL;
940   best_time = GST_CLOCK_TIME_NONE;
941   for (collected = ffmpegmux->collect->data; collected;
942       collected = g_slist_next (collected)) {
943     GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
944     GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect,
945         (GstCollectData *) collect_pad);
946
947     /* if there's no buffer, just continue */
948     if (buffer == NULL) {
949       continue;
950     }
951
952     /* if we have no buffer yet, just use the first one */
953     if (best_pad == NULL) {
954       best_pad = collect_pad;
955       best_time = GST_BUFFER_TIMESTAMP (buffer);
956       goto next_pad;
957     }
958
959     /* if we do have one, only use this one if it's older */
960     if (GST_BUFFER_TIMESTAMP (buffer) < best_time) {
961       best_time = GST_BUFFER_TIMESTAMP (buffer);
962       best_pad = collect_pad;
963     }
964
965   next_pad:
966     gst_buffer_unref (buffer);
967
968     /* Mux buffers with invalid timestamp first */
969     if (!GST_CLOCK_TIME_IS_VALID (best_time))
970       break;
971   }
972
973   /* now handle the buffer, or signal EOS if we have
974    * no buffers left */
975   if (best_pad != NULL) {
976     GstBuffer *buf;
977     AVPacket pkt;
978     gboolean need_free = FALSE;
979 #ifdef GST_EXT_FFMUX_ENHANCEMENT
980     av_init_packet(&pkt);
981     pkt.is_mux = 1; // true
982 #endif
983     /* push out current buffer */
984     buf = gst_collect_pads_pop (ffmpegmux->collect,
985         (GstCollectData *) best_pad);
986
987     ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++;
988
989     /* set time */
990 #ifdef GST_EXT_FFMUX_ENHANCEMENT
991     if(ffmpegmux->context->streams[best_pad->padnum]->codec->codec_type == CODEC_TYPE_VIDEO) {
992         pkt.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buf));
993     } else {
994         pkt.pts = gst_ffmpeg_time_gst_to_ff(GST_BUFFER_TIMESTAMP(buf),
995                                             ffmpegmux->context->streams[best_pad->padnum]->time_base);
996     }
997 #else
998     pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
999         ffmpegmux->context->streams[best_pad->padnum]->time_base);
1000 #endif
1001     pkt.dts = pkt.pts;
1002
1003     if (strcmp (ffmpegmux->context->oformat->name, "gif") == 0) {
1004       AVStream *st = ffmpegmux->context->streams[best_pad->padnum];
1005       AVPicture src, dst;
1006
1007       need_free = TRUE;
1008       pkt.size = st->codec->width * st->codec->height * 3;
1009       pkt.data = g_malloc (pkt.size);
1010
1011       dst.data[0] = pkt.data;
1012       dst.data[1] = NULL;
1013       dst.data[2] = NULL;
1014       dst.linesize[0] = st->codec->width * 3;
1015
1016       gst_ffmpeg_avpicture_fill (&src, GST_BUFFER_DATA (buf),
1017           PIX_FMT_RGB24, st->codec->width, st->codec->height);
1018
1019       av_picture_copy (&dst, &src, PIX_FMT_RGB24,
1020           st->codec->width, st->codec->height);
1021     } else {
1022       pkt.data = GST_BUFFER_DATA (buf);
1023       pkt.size = GST_BUFFER_SIZE (buf);
1024     }
1025
1026     pkt.stream_index = best_pad->padnum;
1027     pkt.flags = 0;
1028
1029     if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
1030       pkt.flags |= PKT_FLAG_KEY;
1031
1032 #ifdef GST_EXT_FFMUX_ENHANCEMENT
1033     if (ffmpegmux->context->streams[best_pad->padnum]->codec->codec_type == CODEC_TYPE_VIDEO) {
1034         static int last_duration = -1;
1035         static int64_t last_dts = -1;
1036         if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1037           pkt.duration = GST_TIME_AS_MSECONDS(GST_BUFFER_DURATION(buf));
1038         } else {
1039           pkt.duration = 0;
1040         }
1041
1042         if (last_dts == -1) {
1043           /* first time */
1044           ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1045         } else {
1046           /* check real duration : current dts - last dts */
1047           if (last_duration != (pkt.dts - last_dts)) {
1048             last_duration = pkt.dts - last_dts;
1049             ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1050           }
1051         }
1052         last_dts = pkt.dts;
1053
1054         if (!GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1055           ffmpegmux->context->streams[best_pad->padnum]->codec->i_frame_number++;
1056         }
1057     } else {
1058       if (GST_BUFFER_DURATION_IS_VALID(buf)) {
1059         pkt.duration =
1060             gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1061             ffmpegmux->context->streams[best_pad->padnum]->time_base);
1062       } else {
1063         pkt.duration = 0;
1064       }
1065     }
1066
1067     update_expected_trailer_size(ffmpegmux);
1068 #else
1069     if (GST_BUFFER_DURATION_IS_VALID (buf))
1070       pkt.duration =
1071           gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1072           ffmpegmux->context->streams[best_pad->padnum]->time_base);
1073     else
1074       pkt.duration = 0;
1075 #endif
1076     av_write_frame (ffmpegmux->context, &pkt);
1077     gst_buffer_unref (buf);
1078     if (need_free)
1079       g_free (pkt.data);
1080   } else {
1081     /* close down */
1082     av_write_trailer (ffmpegmux->context);
1083     ffmpegmux->opened = FALSE;
1084     put_flush_packet (ffmpegmux->context->pb);
1085     url_fclose (ffmpegmux->context->pb);
1086     gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ());
1087     return GST_FLOW_UNEXPECTED;
1088   }
1089
1090   return GST_FLOW_OK;
1091 }
1092
1093 static GstStateChangeReturn
1094 gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
1095 {
1096   GstFlowReturn ret;
1097   GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (element);
1098
1099   switch (transition) {
1100     case GST_STATE_CHANGE_NULL_TO_READY:
1101       break;
1102     case GST_STATE_CHANGE_READY_TO_PAUSED:
1103       gst_collect_pads_start (ffmpegmux->collect);
1104       break;
1105     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1106       break;
1107     case GST_STATE_CHANGE_PAUSED_TO_READY:
1108       gst_collect_pads_stop (ffmpegmux->collect);
1109       break;
1110     default:
1111       break;
1112   }
1113
1114   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1115
1116   switch (transition) {
1117     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1118       break;
1119     case GST_STATE_CHANGE_PAUSED_TO_READY:
1120       gst_tag_setter_reset_tags (GST_TAG_SETTER (ffmpegmux));
1121       if (ffmpegmux->opened) {
1122         ffmpegmux->opened = FALSE;
1123         url_fclose (ffmpegmux->context->pb);
1124       }
1125 #ifdef GST_EXT_FFMUX_ENHANCEMENT
1126     int i = 0;
1127         for(i=0; i < ffmpegmux->context->nb_streams; i++)
1128         {
1129                 ffmpegmux->context->streams[i]->start_time = AV_NOPTS_VALUE;
1130                 ffmpegmux->context->streams[i]->duration = AV_NOPTS_VALUE;    
1131                 ffmpegmux->context->streams[i]->cur_dts = AV_NOPTS_VALUE;
1132
1133         }
1134 #endif
1135       break;
1136     case GST_STATE_CHANGE_READY_TO_NULL:
1137       break;
1138     default:
1139       break;
1140   }
1141
1142   return ret;
1143 }
1144
1145 static GstCaps *
1146 gst_ffmpegmux_get_id_caps (enum CodecID *id_list)
1147 {
1148   GstCaps *caps, *t;
1149   gint i;
1150
1151   caps = gst_caps_new_empty ();
1152   for (i = 0; id_list[i] != CODEC_ID_NONE; i++) {
1153     if ((t = gst_ffmpeg_codecid_to_caps (id_list[i], NULL, TRUE)))
1154       gst_caps_append (caps, t);
1155   }
1156   if (gst_caps_is_empty (caps)) {
1157     gst_caps_unref (caps);
1158     return NULL;
1159   }
1160
1161   return caps;
1162 }
1163
1164 /* set a list of integer values on the caps, e.g. for sample rates */
1165 static void
1166 gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps, const gchar * field,
1167     guint num, const gint * values)
1168 {
1169   GValue list = { 0, };
1170   GValue val = { 0, };
1171   gint i;
1172
1173   g_return_if_fail (GST_CAPS_IS_SIMPLE (caps));
1174
1175   g_value_init (&list, GST_TYPE_LIST);
1176   g_value_init (&val, G_TYPE_INT);
1177
1178   for (i = 0; i < num; ++i) {
1179     g_value_set_int (&val, values[i]);
1180     gst_value_list_append_value (&list, &val);
1181   }
1182
1183   gst_structure_set_value (gst_caps_get_structure (caps, 0), field, &list);
1184
1185   g_value_unset (&val);
1186   g_value_unset (&list);
1187 }
1188
1189 gboolean
1190 gst_ffmpegmux_register (GstPlugin * plugin)
1191 {
1192   GTypeInfo typeinfo = {
1193     sizeof (GstFFMpegMuxClass),
1194     (GBaseInitFunc) gst_ffmpegmux_base_init,
1195     NULL,
1196     (GClassInitFunc) gst_ffmpegmux_class_init,
1197     NULL,
1198     NULL,
1199     sizeof (GstFFMpegMux),
1200     0,
1201     (GInstanceInitFunc) gst_ffmpegmux_init,
1202   };
1203   static const GInterfaceInfo tag_setter_info = {
1204     NULL, NULL, NULL
1205   };
1206   GType type;
1207   AVOutputFormat *in_plugin;
1208
1209   in_plugin = av_oformat_next (NULL);
1210
1211   GST_LOG ("Registering muxers");
1212
1213   while (in_plugin) {
1214     gchar *type_name;
1215     gchar *p;
1216     GstRank rank = GST_RANK_MARGINAL;
1217
1218     if ((!strncmp (in_plugin->name, "u16", 3)) ||
1219         (!strncmp (in_plugin->name, "s16", 3)) ||
1220         (!strncmp (in_plugin->name, "u24", 3)) ||
1221         (!strncmp (in_plugin->name, "s24", 3)) ||
1222         (!strncmp (in_plugin->name, "u8", 2)) ||
1223         (!strncmp (in_plugin->name, "s8", 2)) ||
1224         (!strncmp (in_plugin->name, "u32", 3)) ||
1225         (!strncmp (in_plugin->name, "s32", 3)) ||
1226         (!strncmp (in_plugin->name, "f32", 3)) ||
1227         (!strncmp (in_plugin->name, "f64", 3)) ||
1228         (!strncmp (in_plugin->name, "raw", 3)) ||
1229         (!strncmp (in_plugin->name, "crc", 3)) ||
1230         (!strncmp (in_plugin->name, "null", 4)) ||
1231         (!strncmp (in_plugin->name, "gif", 3)) ||
1232         (!strncmp (in_plugin->name, "frame", 5)) ||
1233         (!strncmp (in_plugin->name, "image", 5)) ||
1234         (!strncmp (in_plugin->name, "mulaw", 5)) ||
1235         (!strncmp (in_plugin->name, "alaw", 4)) ||
1236         (!strncmp (in_plugin->name, "h26", 3)) ||
1237         (!strncmp (in_plugin->name, "rtp", 3)) ||
1238         (!strncmp (in_plugin->name, "ass", 3))
1239         ) {
1240       GST_LOG ("Ignoring muxer %s", in_plugin->name);
1241       goto next;
1242     }
1243
1244     if ((!strncmp (in_plugin->long_name, "raw ", 4))) {
1245       GST_LOG ("Ignoring raw muxer %s", in_plugin->name);
1246       goto next;
1247     }
1248
1249     if (gst_ffmpegmux_get_replacement (in_plugin->name))
1250       rank = GST_RANK_NONE;
1251
1252     /* FIXME : We need a fast way to know whether we have mappings for this
1253      * muxer type. */
1254
1255     /* construct the type */
1256     type_name = g_strdup_printf ("ffmux_%s", in_plugin->name);
1257
1258     p = type_name;
1259
1260     while (*p) {
1261       if (*p == '.')
1262         *p = '_';
1263       p++;
1264     }
1265
1266     type = g_type_from_name (type_name);
1267
1268     if (!type) {
1269       /* create the type now */
1270       type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1271       g_type_set_qdata (type, GST_FFMUX_PARAMS_QDATA, (gpointer) in_plugin);
1272       g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
1273     }
1274
1275     if (!gst_element_register (plugin, type_name, rank, type)) {
1276       g_free (type_name);
1277       return FALSE;
1278     }
1279
1280     g_free (type_name);
1281
1282   next:
1283     in_plugin = av_oformat_next (in_plugin);
1284   }
1285
1286   GST_LOG ("Finished registering muxers");
1287
1288   return TRUE;
1289 }