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