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