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