6b248e433856b9fa5e9cd1301dbee1b46c211e02
[platform/upstream/gst-plugins-good.git] / gst / flv / gstflvmux.c
1 /* GStreamer
2  *
3  * Copyright (c) 2008,2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  * Copyright (c) 2008-2017 Collabora Ltd
5  *  @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
6  *  @author: Vincent Penquerc'h <vincent.penquerch@collabora.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:element-flvmux
26  *
27  * flvmux muxes different streams into an FLV file.
28  *
29  * <refsect2>
30  * <title>Example launch line</title>
31  * |[
32  * gst-launch-1.0 -v flvmux name=mux ! filesink location=test.flv  audiotestsrc samplesperbuffer=44100 num-buffers=10 ! faac ! mux.  videotestsrc num-buffers=250 ! video/x-raw,framerate=25/1 ! x264enc ! mux.
33  * ]| This pipeline encodes a test audio and video stream and muxes both into an FLV file.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <math.h>
42 #include <string.h>
43
44 #include <gst/audio/audio.h>
45
46 #include "gstflvmux.h"
47 #include "amfdefs.h"
48
49 GST_DEBUG_CATEGORY_STATIC (flvmux_debug);
50 #define GST_CAT_DEFAULT flvmux_debug
51
52 enum
53 {
54   PROP_0,
55   PROP_STREAMABLE,
56   PROP_METADATACREATOR
57 };
58
59 #define DEFAULT_STREAMABLE FALSE
60 #define MAX_INDEX_ENTRIES 128
61 #define DEFAULT_METADATACREATOR "GStreamer " PACKAGE_VERSION " FLV muxer"
62
63 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
64     GST_PAD_SRC,
65     GST_PAD_ALWAYS,
66     GST_STATIC_CAPS ("video/x-flv")
67     );
68
69 static GstStaticPadTemplate videosink_templ = GST_STATIC_PAD_TEMPLATE ("video",
70     GST_PAD_SINK,
71     GST_PAD_REQUEST,
72     GST_STATIC_CAPS ("video/x-flash-video; "
73         "video/x-flash-screen; "
74         "video/x-vp6-flash; " "video/x-vp6-alpha; "
75         "video/x-h264, stream-format=avc;")
76     );
77
78 static GstStaticPadTemplate audiosink_templ = GST_STATIC_PAD_TEMPLATE ("audio",
79     GST_PAD_SINK,
80     GST_PAD_REQUEST,
81     GST_STATIC_CAPS
82     ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
83         "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
84         "audio/mpeg, mpegversion = (int) { 4, 2 }, stream-format = (string) raw; "
85         "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
86         "audio/x-raw, format = (string) { U8, S16LE}, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
87         "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
88         "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
89         "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
90     );
91
92 G_DEFINE_TYPE (GstFlvMuxPad, gst_flv_mux_pad, GST_TYPE_AGGREGATOR_PAD);
93
94 #define gst_flv_mux_parent_class parent_class
95 G_DEFINE_TYPE_WITH_CODE (GstFlvMux, gst_flv_mux, GST_TYPE_AGGREGATOR,
96     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
97
98 static GstFlowReturn
99 gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout);
100 static gboolean
101 gst_flv_mux_sink_event (GstAggregator * aggregator, GstAggregatorPad * pad,
102     GstEvent * event);
103
104 static GstAggregatorPad *gst_flv_mux_create_new_pad (GstAggregator * agg,
105     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
106 static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad);
107
108 static gboolean gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad,
109     GstCaps * caps);
110 static gboolean gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad,
111     GstCaps * caps);
112
113 static void gst_flv_mux_get_property (GObject * object,
114     guint prop_id, GValue * value, GParamSpec * pspec);
115 static void gst_flv_mux_set_property (GObject * object,
116     guint prop_id, const GValue * value, GParamSpec * pspec);
117 static void gst_flv_mux_finalize (GObject * object);
118
119 static void gst_flv_mux_reset (GstElement * element);
120 static void gst_flv_mux_reset_pad (GstFlvMuxPad * pad);
121
122 static void gst_flv_mux_pad_finalize (GObject * object);
123
124 static gboolean gst_flv_mux_start (GstAggregator * aggregator);
125 static GstFlowReturn gst_flv_mux_flush (GstAggregator * aggregator);
126 static GstClockTime gst_flv_mux_get_next_time (GstAggregator * aggregator);
127 static GstFlowReturn gst_flv_mux_write_eos (GstFlvMux * mux);
128 static GstFlowReturn gst_flv_mux_write_header (GstFlvMux * mux);
129 static GstFlowReturn gst_flv_mux_rewrite_header (GstFlvMux * mux);
130 static gboolean gst_flv_mux_are_all_pads_eos (GstFlvMux * mux);
131
132
133 static GstFlowReturn
134 gst_flv_mux_pad_flush (GstAggregatorPad * pad, GstAggregator * aggregator)
135 {
136   GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad);
137
138   flvpad->last_timestamp = 0;
139   flvpad->pts = GST_CLOCK_STIME_NONE;
140   flvpad->dts = GST_CLOCK_STIME_NONE;
141
142   return GST_FLOW_OK;
143 }
144
145 static void
146 gst_flv_mux_pad_class_init (GstFlvMuxPadClass * klass)
147 {
148   GstAggregatorPadClass *aggregatorpad_class = (GstAggregatorPadClass *) klass;
149   GObjectClass *gobject_class = (GObjectClass *) klass;
150
151   gobject_class->finalize = gst_flv_mux_pad_finalize;
152
153   aggregatorpad_class->flush = GST_DEBUG_FUNCPTR (gst_flv_mux_pad_flush);
154 }
155
156 static void
157 gst_flv_mux_pad_init (GstFlvMuxPad * pad)
158 {
159   gst_flv_mux_reset_pad (pad);
160 }
161
162 typedef struct
163 {
164   gdouble position;
165   gdouble time;
166 } GstFlvMuxIndexEntry;
167
168 static void
169 gst_flv_mux_index_entry_free (GstFlvMuxIndexEntry * entry)
170 {
171   g_slice_free (GstFlvMuxIndexEntry, entry);
172 }
173
174 static GstBuffer *
175 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
176 {
177   GstBuffer *buf;
178
179   buf = gst_buffer_new ();
180   gst_buffer_append_memory (buf,
181       gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
182           mem, size, 0, size, mem, free_func));
183
184   return buf;
185 }
186
187 static void
188 _gst_buffer_new_and_alloc (gsize size, GstBuffer ** buffer, guint8 ** data)
189 {
190   g_return_if_fail (data != NULL);
191   g_return_if_fail (buffer != NULL);
192
193   *data = g_malloc (size);
194   *buffer = _gst_buffer_new_wrapped (*data, size, g_free);
195 }
196
197 static void
198 gst_flv_mux_class_init (GstFlvMuxClass * klass)
199 {
200   GObjectClass *gobject_class;
201   GstElementClass *gstelement_class;
202   GstAggregatorClass *gstaggregator_class;
203
204   GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
205
206   gobject_class = (GObjectClass *) klass;
207   gstelement_class = (GstElementClass *) klass;
208   gstaggregator_class = (GstAggregatorClass *) klass;
209
210   gobject_class->get_property = gst_flv_mux_get_property;
211   gobject_class->set_property = gst_flv_mux_set_property;
212   gobject_class->finalize = gst_flv_mux_finalize;
213
214   /* FIXME: ideally the right mode of operation should be detected
215    * automatically using queries when parameter not specified. */
216   /**
217    * GstFlvMux:streamable
218    *
219    * If True, the output will be streaming friendly. (ie without indexes and
220    * duration)
221    */
222   g_object_class_install_property (gobject_class, PROP_STREAMABLE,
223       g_param_spec_boolean ("streamable", "streamable",
224           "If set to true, the output should be as if it is to be streamed "
225           "and hence no indexes written or duration written.",
226           DEFAULT_STREAMABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
227   g_object_class_install_property (gobject_class, PROP_METADATACREATOR,
228       g_param_spec_string ("metadatacreator", "metadatacreator",
229           "The value of metadatacreator in the meta packet.",
230           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231
232   gstaggregator_class->create_new_pad =
233       GST_DEBUG_FUNCPTR (gst_flv_mux_create_new_pad);
234   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_flv_mux_release_pad);
235
236   gstaggregator_class->start = GST_DEBUG_FUNCPTR (gst_flv_mux_start);
237   gstaggregator_class->aggregate = GST_DEBUG_FUNCPTR (gst_flv_mux_aggregate);
238   gstaggregator_class->sink_event = GST_DEBUG_FUNCPTR (gst_flv_mux_sink_event);
239   gstaggregator_class->flush = GST_DEBUG_FUNCPTR (gst_flv_mux_flush);
240   gstaggregator_class->get_next_time =
241       GST_DEBUG_FUNCPTR (gst_flv_mux_get_next_time);
242
243   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
244       &videosink_templ, GST_TYPE_FLV_MUX_PAD);
245   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
246       &audiosink_templ, GST_TYPE_FLV_MUX_PAD);
247   gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
248       &src_templ, GST_TYPE_AGGREGATOR_PAD);
249   gst_element_class_set_static_metadata (gstelement_class, "FLV muxer",
250       "Codec/Muxer",
251       "Muxes video/audio streams into a FLV stream",
252       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
253
254   GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
255 }
256
257 static void
258 gst_flv_mux_init (GstFlvMux * mux)
259 {
260   mux->srcpad = GST_AGGREGATOR_CAST (mux)->srcpad;
261
262   /* property */
263   mux->streamable = DEFAULT_STREAMABLE;
264   mux->metadatacreator = g_strdup (DEFAULT_METADATACREATOR);
265
266   mux->new_tags = FALSE;
267
268   gst_flv_mux_reset (GST_ELEMENT (mux));
269 }
270
271 static void
272 gst_flv_mux_finalize (GObject * object)
273 {
274   GstFlvMux *mux = GST_FLV_MUX (object);
275
276   gst_flv_mux_reset (GST_ELEMENT (object));
277   g_free (mux->metadatacreator);
278
279   G_OBJECT_CLASS (gst_flv_mux_parent_class)->finalize (object);
280 }
281
282 static void
283 gst_flv_mux_pad_finalize (GObject * object)
284 {
285   GstFlvMuxPad *pad = GST_FLV_MUX_PAD (object);
286
287   gst_flv_mux_reset_pad (pad);
288
289   G_OBJECT_CLASS (gst_flv_mux_pad_parent_class)->finalize (object);
290 }
291
292 static GstFlowReturn
293 gst_flv_mux_flush (GstAggregator * aggregator)
294 {
295   /* TODO: What is the right behaviour on flush? Should we just ignore it ?
296    * This still needs to be defined. */
297
298   gst_flv_mux_reset (GST_ELEMENT (aggregator));
299   return GST_FLOW_OK;
300 }
301
302 static gboolean
303 gst_flv_mux_start (GstAggregator * aggregator)
304 {
305   gst_flv_mux_reset (GST_ELEMENT (aggregator));
306   return TRUE;
307 }
308
309 static void
310 gst_flv_mux_reset (GstElement * element)
311 {
312   GstFlvMux *mux = GST_FLV_MUX (element);
313
314   g_list_foreach (mux->index, (GFunc) gst_flv_mux_index_entry_free, NULL);
315   g_list_free (mux->index);
316   mux->index = NULL;
317   mux->byte_count = 0;
318
319   mux->duration = GST_CLOCK_TIME_NONE;
320   mux->new_tags = FALSE;
321   mux->first_timestamp = GST_CLOCK_STIME_NONE;
322
323   mux->state = GST_FLV_MUX_STATE_HEADER;
324
325   /* tags */
326   gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
327 }
328
329 /* Extract per-codec relevant tags for
330  * insertion into the metadata later - ie bitrate,
331  * but maybe others in the future */
332 static void
333 gst_flv_mux_store_codec_tags (GstFlvMux * mux,
334     GstFlvMuxPad * flvpad, GstTagList * list)
335 {
336   /* Look for a bitrate as either nominal or actual bitrate tag */
337   if (gst_tag_list_get_uint (list, GST_TAG_NOMINAL_BITRATE, &flvpad->bitrate)
338       || gst_tag_list_get_uint (list, GST_TAG_BITRATE, &flvpad->bitrate)) {
339     GST_DEBUG_OBJECT (mux, "Stored bitrate for pad %" GST_PTR_FORMAT " = %u",
340         flvpad, flvpad->bitrate);
341   }
342 }
343
344 static gboolean
345 gst_flv_mux_sink_event (GstAggregator * aggregator, GstAggregatorPad * pad,
346     GstEvent * event)
347 {
348   GstFlvMux *mux = GST_FLV_MUX (aggregator);
349   GstFlvMuxPad *flvpad = (GstFlvMuxPad *) pad;
350   gboolean ret = TRUE;
351
352   switch (GST_EVENT_TYPE (event)) {
353     case GST_EVENT_CAPS:
354     {
355       GstCaps *caps;
356
357       gst_event_parse_caps (event, &caps);
358
359       if (mux->video_pad == flvpad) {
360         ret = gst_flv_mux_video_pad_setcaps (flvpad, caps);
361       } else if (mux->audio_pad == flvpad) {
362         ret = gst_flv_mux_audio_pad_setcaps (flvpad, caps);
363       } else {
364         g_assert_not_reached ();
365       }
366       break;
367     }
368     case GST_EVENT_TAG:{
369       GstTagList *list;
370       GstTagSetter *setter = GST_TAG_SETTER (mux);
371       const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
372
373       gst_event_parse_tag (event, &list);
374       gst_tag_setter_merge_tags (setter, list, mode);
375       gst_flv_mux_store_codec_tags (mux, flvpad, list);
376       mux->new_tags = TRUE;
377       ret = TRUE;
378       break;
379     }
380     default:
381       break;
382   }
383
384   if (!ret)
385     return FALSE;
386
387   return GST_AGGREGATOR_CLASS (parent_class)->sink_event (aggregator, pad,
388       event);;
389 }
390
391 static gboolean
392 gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
393 {
394   GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
395   gboolean ret = TRUE;
396   GstStructure *s;
397
398   s = gst_caps_get_structure (caps, 0);
399
400   if (strcmp (gst_structure_get_name (s), "video/x-flash-video") == 0) {
401     pad->codec = 2;
402   } else if (strcmp (gst_structure_get_name (s), "video/x-flash-screen") == 0) {
403     pad->codec = 3;
404   } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-flash") == 0) {
405     pad->codec = 4;
406   } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-alpha") == 0) {
407     pad->codec = 5;
408   } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) {
409     pad->codec = 7;
410   } else {
411     ret = FALSE;
412   }
413
414   if (ret && gst_structure_has_field (s, "codec_data")) {
415     const GValue *val = gst_structure_get_value (s, "codec_data");
416
417     if (val)
418       pad->codec_data = gst_buffer_ref (gst_value_get_buffer (val));
419   }
420
421   gst_object_unref (mux);
422
423   return ret;
424 }
425
426 static gboolean
427 gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
428 {
429   GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
430   gboolean ret = TRUE;
431   GstStructure *s;
432
433   s = gst_caps_get_structure (caps, 0);
434
435   if (strcmp (gst_structure_get_name (s), "audio/x-adpcm") == 0) {
436     const gchar *layout = gst_structure_get_string (s, "layout");
437     if (layout && strcmp (layout, "swf") == 0) {
438       pad->codec = 1;
439     } else {
440       ret = FALSE;
441     }
442   } else if (strcmp (gst_structure_get_name (s), "audio/mpeg") == 0) {
443     gint mpegversion;
444
445     if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
446       if (mpegversion == 1) {
447         gint layer;
448
449         if (gst_structure_get_int (s, "layer", &layer) && layer == 3) {
450           gint rate;
451
452           if (gst_structure_get_int (s, "rate", &rate) && rate == 8000)
453             pad->codec = 14;
454           else
455             pad->codec = 2;
456         } else {
457           ret = FALSE;
458         }
459       } else if (mpegversion == 4 || mpegversion == 2) {
460         pad->codec = 10;
461       } else {
462         ret = FALSE;
463       }
464     } else {
465       ret = FALSE;
466     }
467   } else if (strcmp (gst_structure_get_name (s), "audio/x-nellymoser") == 0) {
468     gint rate, channels;
469
470     if (gst_structure_get_int (s, "rate", &rate)
471         && gst_structure_get_int (s, "channels", &channels)) {
472       if (channels == 1 && rate == 16000)
473         pad->codec = 4;
474       else if (channels == 1 && rate == 8000)
475         pad->codec = 5;
476       else
477         pad->codec = 6;
478     } else {
479       pad->codec = 6;
480     }
481   } else if (strcmp (gst_structure_get_name (s), "audio/x-raw") == 0) {
482     GstAudioInfo info;
483
484     if (gst_audio_info_from_caps (&info, caps)) {
485       pad->codec = 3;
486
487       if (GST_AUDIO_INFO_WIDTH (&info) == 8)
488         pad->width = 0;
489       else if (GST_AUDIO_INFO_WIDTH (&info) == 16)
490         pad->width = 1;
491       else
492         ret = FALSE;
493     } else
494       ret = FALSE;
495   } else if (strcmp (gst_structure_get_name (s), "audio/x-alaw") == 0) {
496     pad->codec = 7;
497   } else if (strcmp (gst_structure_get_name (s), "audio/x-mulaw") == 0) {
498     pad->codec = 8;
499   } else if (strcmp (gst_structure_get_name (s), "audio/x-speex") == 0) {
500     pad->codec = 11;
501   } else {
502     ret = FALSE;
503   }
504
505   if (ret) {
506     gint rate, channels;
507
508     if (gst_structure_get_int (s, "rate", &rate)) {
509       if (pad->codec == 10)
510         pad->rate = 3;
511       else if (rate == 5512)
512         pad->rate = 0;
513       else if (rate == 11025)
514         pad->rate = 1;
515       else if (rate == 22050)
516         pad->rate = 2;
517       else if (rate == 44100)
518         pad->rate = 3;
519       else if (rate == 8000 && (pad->codec == 5 || pad->codec == 14))
520         pad->rate = 0;
521       else if (rate == 16000 && (pad->codec == 4 || pad->codec == 11))
522         pad->rate = 0;
523       else
524         ret = FALSE;
525     } else if (pad->codec == 10) {
526       pad->rate = 3;
527     } else {
528       ret = FALSE;
529     }
530
531     if (gst_structure_get_int (s, "channels", &channels)) {
532       if (pad->codec == 4 || pad->codec == 5
533           || pad->codec == 6 || pad->codec == 11)
534         pad->channels = 0;
535       else if (pad->codec == 10)
536         pad->channels = 1;
537       else if (channels == 1)
538         pad->channels = 0;
539       else if (channels == 2)
540         pad->channels = 1;
541       else
542         ret = FALSE;
543     } else if (pad->codec == 4 || pad->codec == 5 || pad->codec == 6) {
544       pad->channels = 0;
545     } else if (pad->codec == 10) {
546       pad->channels = 1;
547     } else {
548       ret = FALSE;
549     }
550
551     if (pad->codec != 3)
552       pad->width = 1;
553   }
554
555   if (ret && gst_structure_has_field (s, "codec_data")) {
556     const GValue *val = gst_structure_get_value (s, "codec_data");
557
558     if (val)
559       pad->codec_data = gst_buffer_ref (gst_value_get_buffer (val));
560   }
561
562   gst_object_unref (mux);
563
564   return ret;
565 }
566
567 static void
568 gst_flv_mux_reset_pad (GstFlvMuxPad * pad)
569 {
570   GST_DEBUG_OBJECT (pad, "resetting pad");
571
572   if (pad->codec_data)
573     gst_buffer_unref (pad->codec_data);
574   pad->codec_data = NULL;
575   pad->codec = G_MAXUINT;
576   pad->rate = G_MAXUINT;
577   pad->width = G_MAXUINT;
578   pad->channels = G_MAXUINT;
579
580   gst_flv_mux_pad_flush (GST_AGGREGATOR_PAD_CAST (pad), NULL);
581 }
582
583 static GstAggregatorPad *
584 gst_flv_mux_create_new_pad (GstAggregator * agg,
585     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
586 {
587   GstElementClass *klass = GST_ELEMENT_GET_CLASS (agg);
588   GstAggregatorPad *aggpad;
589   GstFlvMux *mux = GST_FLV_MUX (agg);
590   GstFlvMuxPad *pad = NULL;
591   const gchar *name = NULL;
592   gboolean video;
593
594   if (mux->state != GST_FLV_MUX_STATE_HEADER) {
595     GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
596     return NULL;
597   }
598
599   if (templ == gst_element_class_get_pad_template (klass, "audio")) {
600     if (mux->audio_pad) {
601       GST_WARNING_OBJECT (mux, "Already have an audio pad");
602       return NULL;
603     }
604     name = "audio";
605     video = FALSE;
606   } else if (templ == gst_element_class_get_pad_template (klass, "video")) {
607     if (mux->video_pad) {
608       GST_WARNING_OBJECT (mux, "Already have a video pad");
609       return NULL;
610     }
611     name = "video";
612     video = TRUE;
613   } else {
614     GST_WARNING_OBJECT (mux, "Invalid template");
615     return NULL;
616   }
617
618   aggpad =
619       GST_AGGREGATOR_CLASS (gst_flv_mux_parent_class)->create_new_pad (agg,
620       templ, name, caps);
621   if (aggpad == NULL)
622     return NULL;
623
624   pad = GST_FLV_MUX_PAD (aggpad);
625
626   gst_flv_mux_reset_pad (pad);
627
628   if (video)
629     mux->video_pad = pad;
630   else
631     mux->audio_pad = pad;
632
633   return aggpad;
634 }
635
636 static void
637 gst_flv_mux_release_pad (GstElement * element, GstPad * pad)
638 {
639   GstFlvMux *mux = GST_FLV_MUX (element);
640   GstFlvMuxPad *flvpad = GST_FLV_MUX_PAD (pad);
641
642   gst_pad_set_active (pad, FALSE);
643   gst_flv_mux_reset_pad (flvpad);
644
645   if (flvpad == mux->video_pad) {
646     mux->video_pad = NULL;
647   } else if (flvpad == mux->audio_pad) {
648     mux->audio_pad = NULL;
649   } else {
650     GST_WARNING_OBJECT (pad, "Pad is not known audio or video pad");
651   }
652
653   gst_element_remove_pad (element, pad);
654 }
655
656 static GstFlowReturn
657 gst_flv_mux_push (GstFlvMux * mux, GstBuffer * buffer)
658 {
659   /* pushing the buffer that rewrites the header will make it no longer be the
660    * total output size in bytes, but it doesn't matter at that point */
661   mux->byte_count += gst_buffer_get_size (buffer);
662
663   return gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (mux), buffer);
664 }
665
666 static GstBuffer *
667 gst_flv_mux_create_header (GstFlvMux * mux)
668 {
669   GstBuffer *header;
670   guint8 *data;
671   gboolean have_audio;
672   gboolean have_video;
673
674   _gst_buffer_new_and_alloc (9 + 4, &header, &data);
675
676   data[0] = 'F';
677   data[1] = 'L';
678   data[2] = 'V';
679   data[3] = 0x01;               /* Version */
680
681   have_audio = (mux->audio_pad && mux->audio_pad->codec != G_MAXUINT);
682   have_video = (mux->video_pad && mux->video_pad->codec != G_MAXUINT);
683
684   data[4] = (have_audio << 2) | have_video;     /* flags */
685   GST_WRITE_UINT32_BE (data + 5, 9);    /* data offset */
686   GST_WRITE_UINT32_BE (data + 9, 0);    /* previous tag size */
687
688   return header;
689 }
690
691 static GstBuffer *
692 gst_flv_mux_preallocate_index (GstFlvMux * mux)
693 {
694   GstBuffer *tmp;
695   guint8 *data;
696   gint preallocate_size;
697
698   /* preallocate index of size:
699    *  - 'keyframes' ECMA array key: 2 + 9 = 11 bytes
700    *  - nested ECMA array header, length and end marker: 8 bytes
701    *  - 'times' and 'filepositions' keys: 22 bytes
702    *  - two strict arrays headers and lengths: 10 bytes
703    *  - each index entry: 18 bytes
704    */
705   preallocate_size = 11 + 8 + 22 + 10 + MAX_INDEX_ENTRIES * 18;
706   GST_DEBUG_OBJECT (mux, "preallocating %d bytes for the index",
707       preallocate_size);
708
709   _gst_buffer_new_and_alloc (preallocate_size, &tmp, &data);
710
711   /* prefill the space with a gstfiller: <spaces> script tag variable */
712   GST_WRITE_UINT16_BE (data, 9);        /* 9 characters */
713   memcpy (data + 2, "gstfiller", 9);
714   GST_WRITE_UINT8 (data + 11, AMF0_STRING_MARKER);      /* a string value */
715   GST_WRITE_UINT16_BE (data + 12, preallocate_size - 14);
716   memset (data + 14, ' ', preallocate_size - 14);       /* the rest is spaces */
717   return tmp;
718 }
719
720 static GstBuffer *
721 gst_flv_mux_create_number_script_value (const gchar * name, gdouble value)
722 {
723   GstBuffer *tmp;
724   guint8 *data;
725   gsize len = strlen (name);
726
727   _gst_buffer_new_and_alloc (2 + len + 1 + 8, &tmp, &data);
728
729   GST_WRITE_UINT16_BE (data, len);
730   data += 2;                    /* name length */
731   memcpy (data, name, len);
732   data += len;
733   *data++ = AMF0_NUMBER_MARKER; /* double type */
734   GST_WRITE_DOUBLE_BE (data, value);
735
736   return tmp;
737 }
738
739 static GstBuffer *
740 gst_flv_mux_create_metadata (GstFlvMux * mux, gboolean full)
741 {
742   const GstTagList *tags;
743   GstBuffer *script_tag, *tmp;
744   GstMapInfo map;
745   guint8 *data;
746   gint i, n_tags, tags_written = 0;
747
748   tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
749
750   GST_DEBUG_OBJECT (mux, "tags = %" GST_PTR_FORMAT, tags);
751
752   /* FIXME perhaps some bytewriter'ing here ... */
753
754   _gst_buffer_new_and_alloc (11, &script_tag, &data);
755
756   data[0] = 18;
757
758   /* Data size, unknown for now */
759   data[1] = 0;
760   data[2] = 0;
761   data[3] = 0;
762
763   /* Timestamp */
764   data[4] = data[5] = data[6] = data[7] = 0;
765
766   /* Stream ID */
767   data[8] = data[9] = data[10] = 0;
768
769   _gst_buffer_new_and_alloc (13, &tmp, &data);
770   data[0] = AMF0_STRING_MARKER; /* string */
771   data[1] = 0;
772   data[2] = 10;                 /* length 10 */
773   memcpy (&data[3], "onMetaData", 10);
774
775   script_tag = gst_buffer_append (script_tag, tmp);
776
777   n_tags = (tags) ? gst_tag_list_n_tags (tags) : 0;
778   _gst_buffer_new_and_alloc (5, &tmp, &data);
779   data[0] = 8;                  /* ECMA array */
780   GST_WRITE_UINT32_BE (data + 1, n_tags);
781   script_tag = gst_buffer_append (script_tag, tmp);
782
783   if (!full)
784     goto tags;
785
786   /* Some players expect the 'duration' to be always set. Fill it out later,
787      after querying the pads or after getting EOS */
788   if (!mux->streamable) {
789     tmp = gst_flv_mux_create_number_script_value ("duration", 86400);
790     script_tag = gst_buffer_append (script_tag, tmp);
791     tags_written++;
792
793     /* Sometimes the information about the total file size is useful for the
794        player. It will be filled later, after getting EOS */
795     tmp = gst_flv_mux_create_number_script_value ("filesize", 0);
796     script_tag = gst_buffer_append (script_tag, tmp);
797     tags_written++;
798
799     /* Preallocate space for the index to be written at EOS */
800     tmp = gst_flv_mux_preallocate_index (mux);
801     script_tag = gst_buffer_append (script_tag, tmp);
802   } else {
803     GST_DEBUG_OBJECT (mux, "not preallocating index, streamable mode");
804   }
805
806 tags:
807   for (i = 0; tags && i < n_tags; i++) {
808     const gchar *tag_name = gst_tag_list_nth_tag_name (tags, i);
809     if (!strcmp (tag_name, GST_TAG_DURATION)) {
810       guint64 dur;
811
812       if (!gst_tag_list_get_uint64 (tags, GST_TAG_DURATION, &dur))
813         continue;
814       mux->duration = dur;
815     } else if (!strcmp (tag_name, GST_TAG_ARTIST) ||
816         !strcmp (tag_name, GST_TAG_TITLE)) {
817       gchar *s;
818       const gchar *t = NULL;
819
820       if (!strcmp (tag_name, GST_TAG_ARTIST))
821         t = "creator";
822       else if (!strcmp (tag_name, GST_TAG_TITLE))
823         t = "title";
824
825       if (!gst_tag_list_get_string (tags, tag_name, &s))
826         continue;
827
828       _gst_buffer_new_and_alloc (2 + strlen (t) + 1 + 2 + strlen (s),
829           &tmp, &data);
830       data[0] = 0;              /* tag name length */
831       data[1] = strlen (t);
832       memcpy (&data[2], t, strlen (t));
833       data[2 + strlen (t)] = 2; /* string */
834       data[3 + strlen (t)] = (strlen (s) >> 8) & 0xff;
835       data[4 + strlen (t)] = (strlen (s)) & 0xff;
836       memcpy (&data[5 + strlen (t)], s, strlen (s));
837       script_tag = gst_buffer_append (script_tag, tmp);
838
839       g_free (s);
840       tags_written++;
841     }
842   }
843
844   if (!full)
845     goto end;
846
847   if (mux->duration == GST_CLOCK_TIME_NONE) {
848     GList *l;
849     guint64 dur;
850
851     for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
852       GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
853
854       if (gst_pad_peer_query_duration (GST_PAD (pad), GST_FORMAT_TIME,
855               (gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) {
856         if (mux->duration == GST_CLOCK_TIME_NONE)
857           mux->duration = dur;
858         else
859           mux->duration = MAX (dur, mux->duration);
860       }
861     }
862   }
863
864   if (!mux->streamable && mux->duration != GST_CLOCK_TIME_NONE) {
865     gdouble d;
866     GstMapInfo map;
867
868     d = gst_guint64_to_gdouble (mux->duration);
869     d /= (gdouble) GST_SECOND;
870
871     GST_DEBUG_OBJECT (mux, "determined the duration to be %f", d);
872     gst_buffer_map (script_tag, &map, GST_MAP_WRITE);
873     GST_WRITE_DOUBLE_BE (map.data + 29 + 2 + 8 + 1, d);
874     gst_buffer_unmap (script_tag, &map);
875   }
876
877   if (mux->video_pad && mux->video_pad->codec != G_MAXUINT) {
878     GstCaps *caps = NULL;
879
880     if (mux->video_pad)
881       caps = gst_pad_get_current_caps (GST_PAD (mux->video_pad));
882
883     if (caps != NULL) {
884       GstStructure *s;
885       gint size;
886       gint num, den;
887
888       GST_DEBUG_OBJECT (mux, "putting videocodecid %d in the metadata",
889           mux->video_pad->codec);
890
891       tmp = gst_flv_mux_create_number_script_value ("videocodecid",
892           mux->video_pad->codec);
893       script_tag = gst_buffer_append (script_tag, tmp);
894       tags_written++;
895
896       s = gst_caps_get_structure (caps, 0);
897       gst_caps_unref (caps);
898
899       if (gst_structure_get_int (s, "width", &size)) {
900         GST_DEBUG_OBJECT (mux, "putting width %d in the metadata", size);
901
902         tmp = gst_flv_mux_create_number_script_value ("width", size);
903         script_tag = gst_buffer_append (script_tag, tmp);
904         tags_written++;
905       }
906
907       if (gst_structure_get_int (s, "height", &size)) {
908         GST_DEBUG_OBJECT (mux, "putting height %d in the metadata", size);
909
910         tmp = gst_flv_mux_create_number_script_value ("height", size);
911         script_tag = gst_buffer_append (script_tag, tmp);
912         tags_written++;
913       }
914
915       if (gst_structure_get_fraction (s, "pixel-aspect-ratio", &num, &den)) {
916         gdouble d;
917
918         d = num;
919         GST_DEBUG_OBJECT (mux, "putting AspectRatioX %f in the metadata", d);
920
921         tmp = gst_flv_mux_create_number_script_value ("AspectRatioX", d);
922         script_tag = gst_buffer_append (script_tag, tmp);
923         tags_written++;
924
925         d = den;
926         GST_DEBUG_OBJECT (mux, "putting AspectRatioY %f in the metadata", d);
927
928         tmp = gst_flv_mux_create_number_script_value ("AspectRatioY", d);
929         script_tag = gst_buffer_append (script_tag, tmp);
930         tags_written++;
931       }
932
933       if (gst_structure_get_fraction (s, "framerate", &num, &den)) {
934         gdouble d;
935
936         gst_util_fraction_to_double (num, den, &d);
937         GST_DEBUG_OBJECT (mux, "putting framerate %f in the metadata", d);
938
939         tmp = gst_flv_mux_create_number_script_value ("framerate", d);
940         script_tag = gst_buffer_append (script_tag, tmp);
941         tags_written++;
942       }
943
944       GST_DEBUG_OBJECT (mux, "putting videodatarate %u KB/s in the metadata",
945           mux->video_pad->bitrate / 1024);
946       tmp = gst_flv_mux_create_number_script_value ("videodatarate",
947           mux->video_pad->bitrate / 1024);
948       script_tag = gst_buffer_append (script_tag, tmp);
949       tags_written++;
950     }
951   }
952
953   if (mux->audio_pad && mux->audio_pad->codec != G_MAXUINT) {
954     GST_DEBUG_OBJECT (mux, "putting audiocodecid %d in the metadata",
955         mux->audio_pad->codec);
956
957     tmp = gst_flv_mux_create_number_script_value ("audiocodecid",
958         mux->audio_pad->codec);
959     script_tag = gst_buffer_append (script_tag, tmp);
960     tags_written++;
961
962     GST_DEBUG_OBJECT (mux, "putting audiodatarate %u KB/s in the metadata",
963         mux->audio_pad->bitrate / 1024);
964     tmp = gst_flv_mux_create_number_script_value ("audiodatarate",
965         mux->audio_pad->bitrate / 1024);
966     script_tag = gst_buffer_append (script_tag, tmp);
967     tags_written++;
968   }
969
970   _gst_buffer_new_and_alloc (2 + 15 + 1 + 2 + strlen (mux->metadatacreator),
971       &tmp, &data);
972   data[0] = 0;                  /* 15 bytes name */
973   data[1] = 15;
974   memcpy (&data[2], "metadatacreator", 15);
975   data[17] = 2;                 /* string */
976   data[18] = (strlen (mux->metadatacreator) >> 8) & 0xff;
977   data[19] = (strlen (mux->metadatacreator)) & 0xff;
978   memcpy (&data[20], mux->metadatacreator, strlen (mux->metadatacreator));
979   script_tag = gst_buffer_append (script_tag, tmp);
980
981   tags_written++;
982
983   {
984     GTimeVal tv = { 0, };
985     time_t secs;
986     struct tm *tm;
987     gchar *s;
988     static const gchar *weekdays[] = {
989       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
990     };
991     static const gchar *months[] = {
992       "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
993       "Aug", "Sep", "Oct", "Nov", "Dec"
994     };
995
996     g_get_current_time (&tv);
997     secs = tv.tv_sec;
998     tm = gmtime (&secs);
999
1000     s = g_strdup_printf ("%s %s %d %02d:%02d:%02d %d", weekdays[tm->tm_wday],
1001         months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1002         tm->tm_year + 1900);
1003
1004     _gst_buffer_new_and_alloc (2 + 12 + 1 + 2 + strlen (s), &tmp, &data);
1005     data[0] = 0;                /* 12 bytes name */
1006     data[1] = 12;
1007     memcpy (&data[2], "creationdate", 12);
1008     data[14] = 2;               /* string */
1009     data[15] = (strlen (s) >> 8) & 0xff;
1010     data[16] = (strlen (s)) & 0xff;
1011     memcpy (&data[17], s, strlen (s));
1012     script_tag = gst_buffer_append (script_tag, tmp);
1013
1014     g_free (s);
1015     tags_written++;
1016   }
1017
1018 end:
1019
1020   if (!tags_written) {
1021     gst_buffer_unref (script_tag);
1022     script_tag = NULL;
1023     goto exit;
1024   }
1025
1026   _gst_buffer_new_and_alloc (2 + 0 + 1, &tmp, &data);
1027   data[0] = 0;                  /* 0 byte size */
1028   data[1] = 0;
1029   data[2] = 9;                  /* end marker */
1030   script_tag = gst_buffer_append (script_tag, tmp);
1031
1032
1033   _gst_buffer_new_and_alloc (4, &tmp, &data);
1034   GST_WRITE_UINT32_BE (data, gst_buffer_get_size (script_tag));
1035   script_tag = gst_buffer_append (script_tag, tmp);
1036
1037   gst_buffer_map (script_tag, &map, GST_MAP_WRITE);
1038   map.data[1] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 16) & 0xff;
1039   map.data[2] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 8) & 0xff;
1040   map.data[3] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 0) & 0xff;
1041
1042   GST_WRITE_UINT32_BE (map.data + 11 + 13 + 1, tags_written);
1043   gst_buffer_unmap (script_tag, &map);
1044
1045 exit:
1046   return script_tag;
1047 }
1048
1049 static GstBuffer *
1050 gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer,
1051     GstFlvMuxPad * pad, gboolean is_codec_data)
1052 {
1053   GstBuffer *tag;
1054   GstMapInfo map;
1055   guint size;
1056   guint32 pts, dts, cts;
1057   guint8 *data, *bdata = NULL;
1058   gsize bsize = 0;
1059
1060   if (!GST_CLOCK_STIME_IS_VALID (pad->dts)) {
1061     pts = dts = pad->last_timestamp / GST_MSECOND;
1062   } else {
1063     pts = pad->pts / GST_MSECOND;
1064     dts = pad->dts / GST_MSECOND;
1065   }
1066
1067   /* Be safe in case TS are buggy */
1068   if (pts > dts)
1069     cts = pts - dts;
1070   else
1071     cts = 0;
1072
1073   /* Timestamp must start at zero */
1074   if (GST_CLOCK_STIME_IS_VALID (mux->first_timestamp)) {
1075     dts -= mux->first_timestamp / GST_MSECOND;
1076     pts = dts + cts;
1077   }
1078
1079   GST_LOG_OBJECT (mux, "got pts %i dts %i cts %i", pts, dts, cts);
1080
1081   if (buffer != NULL) {
1082     gst_buffer_map (buffer, &map, GST_MAP_READ);
1083     bdata = map.data;
1084     bsize = map.size;
1085   }
1086
1087   size = 11;
1088   if (mux->video_pad == pad) {
1089     size += 1;
1090     if (pad->codec == 7)
1091       size += 4 + bsize;
1092     else
1093       size += bsize;
1094   } else {
1095     size += 1;
1096     if (pad->codec == 10)
1097       size += 1 + bsize;
1098     else
1099       size += bsize;
1100   }
1101   size += 4;
1102
1103   _gst_buffer_new_and_alloc (size, &tag, &data);
1104   memset (data, 0, size);
1105
1106   data[0] = (mux->video_pad == pad) ? 9 : 8;
1107
1108   data[1] = ((size - 11 - 4) >> 16) & 0xff;
1109   data[2] = ((size - 11 - 4) >> 8) & 0xff;
1110   data[3] = ((size - 11 - 4) >> 0) & 0xff;
1111
1112   GST_WRITE_UINT24_BE (data + 4, dts);
1113   data[7] = (((guint) dts) >> 24) & 0xff;
1114
1115   data[8] = data[9] = data[10] = 0;
1116
1117   if (mux->video_pad == pad) {
1118     if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
1119       data[11] |= 2 << 4;
1120     else
1121       data[11] |= 1 << 4;
1122
1123     data[11] |= pad->codec & 0x0f;
1124
1125     if (pad->codec == 7) {
1126       if (is_codec_data) {
1127         data[12] = 0;
1128         GST_WRITE_UINT24_BE (data + 13, 0);
1129       } else if (bsize == 0) {
1130         /* AVC end of sequence */
1131         data[12] = 2;
1132         GST_WRITE_UINT24_BE (data + 13, 0);
1133       } else {
1134         /* ACV NALU */
1135         data[12] = 1;
1136         GST_WRITE_UINT24_BE (data + 13, cts);
1137       }
1138       memcpy (data + 11 + 1 + 4, bdata, bsize);
1139     } else {
1140       memcpy (data + 11 + 1, bdata, bsize);
1141     }
1142   } else {
1143     data[11] |= (pad->codec << 4) & 0xf0;
1144     data[11] |= (pad->rate << 2) & 0x0c;
1145     data[11] |= (pad->width << 1) & 0x02;
1146     data[11] |= (pad->channels << 0) & 0x01;
1147
1148     GST_DEBUG_OBJECT (mux, "Creating byte %02x with "
1149         "codec:%d, rate:%d, width:%d, channels:%d",
1150         data[11], pad->codec, pad->rate, pad->width, pad->channels);
1151
1152     if (pad->codec == 10) {
1153       data[12] = is_codec_data ? 0 : 1;
1154
1155       memcpy (data + 11 + 1 + 1, bdata, bsize);
1156     } else {
1157       memcpy (data + 11 + 1, bdata, bsize);
1158     }
1159   }
1160
1161   if (buffer)
1162     gst_buffer_unmap (buffer, &map);
1163
1164   GST_WRITE_UINT32_BE (data + size - 4, size - 4);
1165
1166   GST_BUFFER_PTS (tag) = GST_CLOCK_TIME_NONE;
1167   GST_BUFFER_DTS (tag) = GST_CLOCK_TIME_NONE;
1168   GST_BUFFER_DURATION (tag) = GST_CLOCK_TIME_NONE;
1169
1170   if (buffer) {
1171     /* if we are streamable we copy over timestamps and offsets,
1172        if not just copy the offsets */
1173     if (mux->streamable) {
1174       GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1175
1176       if (gst_segment_to_running_time_full (&GST_AGGREGATOR_PAD (pad)->segment,
1177               GST_FORMAT_TIME, GST_BUFFER_DTS_OR_PTS (buffer),
1178               &timestamp) == 1) {
1179         GST_BUFFER_PTS (tag) = timestamp;
1180         GST_BUFFER_DURATION (tag) = GST_BUFFER_DURATION (buffer);
1181       }
1182       GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_NONE;
1183       GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_NONE;
1184     } else {
1185       GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer);
1186       GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer);
1187     }
1188
1189     /* mark the buffer if it's an audio buffer and there's also video being muxed
1190      * or it's a video interframe */
1191     if (mux->video_pad == pad &&
1192         GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
1193       GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT);
1194   } else {
1195     GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT);
1196     GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) =
1197         GST_BUFFER_OFFSET_NONE;
1198   }
1199
1200   return tag;
1201 }
1202
1203 static inline GstBuffer *
1204 gst_flv_mux_buffer_to_tag (GstFlvMux * mux, GstBuffer * buffer,
1205     GstFlvMuxPad * pad)
1206 {
1207   return gst_flv_mux_buffer_to_tag_internal (mux, buffer, pad, FALSE);
1208 }
1209
1210 static inline GstBuffer *
1211 gst_flv_mux_codec_data_buffer_to_tag (GstFlvMux * mux, GstBuffer * buffer,
1212     GstFlvMuxPad * pad)
1213 {
1214   return gst_flv_mux_buffer_to_tag_internal (mux, buffer, pad, TRUE);
1215 }
1216
1217 static inline GstBuffer *
1218 gst_flv_mux_eos_to_tag (GstFlvMux * mux, GstFlvMuxPad * pad)
1219 {
1220   return gst_flv_mux_buffer_to_tag_internal (mux, NULL, pad, FALSE);
1221 }
1222
1223 static void
1224 gst_flv_mux_put_buffer_in_streamheader (GValue * streamheader,
1225     GstBuffer * buffer)
1226 {
1227   GValue value = { 0 };
1228   GstBuffer *buf;
1229
1230   g_value_init (&value, GST_TYPE_BUFFER);
1231   buf = gst_buffer_copy (buffer);
1232   gst_value_set_buffer (&value, buf);
1233   gst_buffer_unref (buf);
1234   gst_value_array_append_value (streamheader, &value);
1235   g_value_unset (&value);
1236 }
1237
1238 static GstFlowReturn
1239 gst_flv_mux_write_header (GstFlvMux * mux)
1240 {
1241   GstBuffer *header, *metadata;
1242   GstBuffer *video_codec_data, *audio_codec_data;
1243   GstCaps *caps;
1244   GstStructure *structure;
1245   GValue streamheader = { 0 };
1246   GList *l;
1247   GstFlowReturn ret;
1248
1249   /* if not streaming, check if downstream is seekable */
1250   if (!mux->streamable) {
1251     gboolean seekable;
1252     GstQuery *query;
1253
1254     query = gst_query_new_seeking (GST_FORMAT_BYTES);
1255     if (gst_pad_peer_query (mux->srcpad, query)) {
1256       gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
1257       GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not ");
1258     } else {
1259       /* have to assume seeking is supported if query not handled downstream */
1260       GST_WARNING_OBJECT (mux, "downstream did not handle seeking query");
1261       seekable = FALSE;
1262     }
1263     if (!seekable) {
1264       mux->streamable = TRUE;
1265       g_object_notify (G_OBJECT (mux), "streamable");
1266       GST_WARNING_OBJECT (mux, "downstream is not seekable, but "
1267           "streamable=false. Will ignore that and create streamable output "
1268           "instead");
1269     }
1270     gst_query_unref (query);
1271   }
1272
1273   header = gst_flv_mux_create_header (mux);
1274   metadata = gst_flv_mux_create_metadata (mux, TRUE);
1275   video_codec_data = NULL;
1276   audio_codec_data = NULL;
1277
1278   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) {
1279     GstFlvMuxPad *pad = l->data;
1280
1281     /* Get H.264 and AAC codec data, if present */
1282     if (pad && mux->video_pad == pad && pad->codec == 7) {
1283       if (pad->codec_data == NULL)
1284         GST_WARNING_OBJECT (mux, "Codec data for video stream not found, "
1285             "output might not be playable");
1286       else
1287         video_codec_data =
1288             gst_flv_mux_codec_data_buffer_to_tag (mux, pad->codec_data, pad);
1289     } else if (pad && mux->audio_pad == pad && pad->codec == 10) {
1290       if (pad->codec_data == NULL)
1291         GST_WARNING_OBJECT (mux, "Codec data for audio stream not found, "
1292             "output might not be playable");
1293       else
1294         audio_codec_data =
1295             gst_flv_mux_codec_data_buffer_to_tag (mux, pad->codec_data, pad);
1296     }
1297   }
1298
1299   /* mark buffers that will go in the streamheader */
1300   GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_HEADER);
1301   GST_BUFFER_FLAG_SET (metadata, GST_BUFFER_FLAG_HEADER);
1302   if (video_codec_data != NULL) {
1303     GST_BUFFER_FLAG_SET (video_codec_data, GST_BUFFER_FLAG_HEADER);
1304     /* mark as a delta unit, so downstream will not try to synchronize on that
1305      * buffer - to actually start playback you need a real video keyframe */
1306     GST_BUFFER_FLAG_SET (video_codec_data, GST_BUFFER_FLAG_DELTA_UNIT);
1307   }
1308   if (audio_codec_data != NULL) {
1309     GST_BUFFER_FLAG_SET (audio_codec_data, GST_BUFFER_FLAG_HEADER);
1310   }
1311
1312   /* put buffers in streamheader */
1313   g_value_init (&streamheader, GST_TYPE_ARRAY);
1314   gst_flv_mux_put_buffer_in_streamheader (&streamheader, header);
1315   gst_flv_mux_put_buffer_in_streamheader (&streamheader, metadata);
1316   if (video_codec_data != NULL)
1317     gst_flv_mux_put_buffer_in_streamheader (&streamheader, video_codec_data);
1318   if (audio_codec_data != NULL)
1319     gst_flv_mux_put_buffer_in_streamheader (&streamheader, audio_codec_data);
1320
1321   /* create the caps and put the streamheader in them */
1322   caps = gst_caps_new_empty_simple ("video/x-flv");
1323   structure = gst_caps_get_structure (caps, 0);
1324   gst_structure_set_value (structure, "streamheader", &streamheader);
1325   g_value_unset (&streamheader);
1326
1327   gst_aggregator_set_src_caps (GST_AGGREGATOR_CAST (mux), caps);
1328
1329   gst_caps_unref (caps);
1330
1331   /* push the header buffer, the metadata and the codec info, if any */
1332   ret = gst_flv_mux_push (mux, header);
1333   if (ret != GST_FLOW_OK)
1334     goto failure_header;
1335   ret = gst_flv_mux_push (mux, metadata);
1336   if (ret != GST_FLOW_OK)
1337     goto failure_metadata;
1338   if (video_codec_data != NULL) {
1339     ret = gst_flv_mux_push (mux, video_codec_data);
1340     if (ret != GST_FLOW_OK)
1341       goto failure_video_codec_data;
1342   }
1343   if (audio_codec_data != NULL) {
1344     ret = gst_flv_mux_push (mux, audio_codec_data);
1345     if (ret != GST_FLOW_OK)
1346       goto failure_audio_codec_data;
1347   }
1348   return GST_FLOW_OK;
1349
1350 failure_header:
1351   gst_buffer_unref (metadata);
1352
1353 failure_metadata:
1354   if (video_codec_data != NULL)
1355     gst_buffer_unref (video_codec_data);
1356
1357 failure_video_codec_data:
1358   if (audio_codec_data != NULL)
1359     gst_buffer_unref (audio_codec_data);
1360
1361 failure_audio_codec_data:
1362   return ret;
1363 }
1364
1365 static GstClockTime
1366 gst_flv_mux_segment_to_running_time (const GstSegment * segment, GstClockTime t)
1367 {
1368   /* we can get a dts before the segment, if dts < pts and pts is inside
1369    * the segment, so we consider early times as 0 */
1370   if (t < segment->start)
1371     return 0;
1372   return gst_segment_to_running_time (segment, GST_FORMAT_TIME, t);
1373 }
1374
1375 static void
1376 gst_flv_mux_update_index (GstFlvMux * mux, GstBuffer * buffer,
1377     GstFlvMuxPad * pad)
1378 {
1379   /*
1380    * Add the tag byte offset and to the index if it's a valid seek point, which
1381    * means it's either a video keyframe or if there is no video pad (in that
1382    * case every FLV tag is a valid seek point)
1383    */
1384   if (mux->video_pad == pad &&
1385       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
1386     return;
1387
1388   if (GST_BUFFER_PTS_IS_VALID (buffer)) {
1389     GstFlvMuxIndexEntry *entry = g_slice_new (GstFlvMuxIndexEntry);
1390     GstClockTime pts =
1391         gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
1392         (pad)->segment, GST_BUFFER_PTS (buffer));
1393     entry->position = mux->byte_count;
1394     entry->time = gst_guint64_to_gdouble (pts) / GST_SECOND;
1395     mux->index = g_list_prepend (mux->index, entry);
1396   }
1397 }
1398
1399 static GstFlowReturn
1400 gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvMuxPad * pad,
1401     GstBuffer * buffer)
1402 {
1403   GstBuffer *tag;
1404   GstFlowReturn ret;
1405   GstClockTime dts =
1406       gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD (pad)->segment,
1407       GST_BUFFER_DTS (buffer));
1408
1409   /* clipping function arranged for running_time */
1410
1411   if (!mux->streamable)
1412     gst_flv_mux_update_index (mux, buffer, pad);
1413
1414   tag = gst_flv_mux_buffer_to_tag (mux, buffer, pad);
1415
1416   gst_buffer_unref (buffer);
1417
1418   ret = gst_flv_mux_push (mux, tag);
1419
1420   if (ret == GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (dts))
1421     pad->last_timestamp = dts;
1422
1423
1424   return ret;
1425 }
1426
1427 static guint64
1428 gst_flv_mux_determine_duration (GstFlvMux * mux)
1429 {
1430   GList *l;
1431   GstClockTime duration = GST_CLOCK_TIME_NONE;
1432
1433   GST_DEBUG_OBJECT (mux, "trying to determine the duration "
1434       "from pad timestamps");
1435
1436   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l != NULL; l = l->next) {
1437     GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
1438
1439     if (pad && (pad->last_timestamp != GST_CLOCK_TIME_NONE)) {
1440       if (duration == GST_CLOCK_TIME_NONE)
1441         duration = pad->last_timestamp;
1442       else
1443         duration = MAX (duration, pad->last_timestamp);
1444     }
1445   }
1446
1447   return duration;
1448 }
1449
1450 static gboolean
1451 gst_flv_mux_are_all_pads_eos (GstFlvMux * mux)
1452 {
1453   GList *l;
1454
1455   for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
1456     GstFlvMuxPad *pad = GST_FLV_MUX_PAD (l->data);
1457
1458     if (!gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (pad)))
1459       return FALSE;
1460   }
1461   return TRUE;
1462 }
1463
1464 static GstFlowReturn
1465 gst_flv_mux_write_eos (GstFlvMux * mux)
1466 {
1467   GstBuffer *tag;
1468
1469   if (mux->video_pad == NULL)
1470     return GST_FLOW_OK;
1471
1472   tag = gst_flv_mux_eos_to_tag (mux, mux->video_pad);
1473
1474   return gst_flv_mux_push (mux, tag);
1475 }
1476
1477 static GstFlowReturn
1478 gst_flv_mux_rewrite_header (GstFlvMux * mux)
1479 {
1480   GstBuffer *rewrite, *index, *tmp;
1481   GstEvent *event;
1482   guint8 *data;
1483   gdouble d;
1484   GList *l;
1485   guint32 index_len, allocate_size;
1486   guint32 i, index_skip;
1487   GstSegment segment;
1488   GstClockTime dur;
1489
1490   if (mux->streamable)
1491     return GST_FLOW_OK;
1492
1493   /* seek back to the preallocated index space */
1494   gst_segment_init (&segment, GST_FORMAT_BYTES);
1495   segment.start = segment.time = 13 + 29;
1496   event = gst_event_new_segment (&segment);
1497   if (!gst_pad_push_event (mux->srcpad, event)) {
1498     GST_WARNING_OBJECT (mux, "Seek to rewrite header failed");
1499     return GST_FLOW_OK;
1500   }
1501
1502   /* determine duration now based on our own timestamping,
1503    * so that it is likely many times better and consistent
1504    * than whatever obtained by some query */
1505   dur = gst_flv_mux_determine_duration (mux);
1506   if (dur != GST_CLOCK_TIME_NONE)
1507     mux->duration = dur;
1508
1509   /* rewrite the duration tag */
1510   d = gst_guint64_to_gdouble (mux->duration);
1511   d /= (gdouble) GST_SECOND;
1512
1513   GST_DEBUG_OBJECT (mux, "determined the final duration to be %f", d);
1514
1515   rewrite = gst_flv_mux_create_number_script_value ("duration", d);
1516
1517   /* rewrite the filesize tag */
1518   d = gst_guint64_to_gdouble (mux->byte_count);
1519
1520   GST_DEBUG_OBJECT (mux, "putting total filesize %f in the metadata", d);
1521
1522   tmp = gst_flv_mux_create_number_script_value ("filesize", d);
1523   rewrite = gst_buffer_append (rewrite, tmp);
1524
1525   if (!mux->index) {
1526     /* no index, so push buffer and return */
1527     return gst_flv_mux_push (mux, rewrite);
1528   }
1529
1530   /* rewrite the index */
1531   mux->index = g_list_reverse (mux->index);
1532   index_len = g_list_length (mux->index);
1533
1534   /* We write at most MAX_INDEX_ENTRIES elements */
1535   if (index_len > MAX_INDEX_ENTRIES) {
1536     index_skip = 1 + index_len / MAX_INDEX_ENTRIES;
1537     index_len = (index_len + index_skip - 1) / index_skip;
1538   } else {
1539     index_skip = 1;
1540   }
1541
1542   GST_DEBUG_OBJECT (mux, "Index length is %d", index_len);
1543   /* see size calculation in gst_flv_mux_preallocate_index */
1544   allocate_size = 11 + 8 + 22 + 10 + index_len * 18;
1545   GST_DEBUG_OBJECT (mux, "Allocating %d bytes for index", allocate_size);
1546   _gst_buffer_new_and_alloc (allocate_size, &index, &data);
1547
1548   GST_WRITE_UINT16_BE (data, 9);        /* the 'keyframes' key */
1549   memcpy (data + 2, "keyframes", 9);
1550   GST_WRITE_UINT8 (data + 11, 8);       /* nested ECMA array */
1551   GST_WRITE_UINT32_BE (data + 12, 2);   /* two elements */
1552   GST_WRITE_UINT16_BE (data + 16, 5);   /* first string key: 'times' */
1553   memcpy (data + 18, "times", 5);
1554   GST_WRITE_UINT8 (data + 23, 10);      /* strict array */
1555   GST_WRITE_UINT32_BE (data + 24, index_len);
1556   data += 28;
1557
1558   /* the keyframes' times */
1559   for (i = 0, l = mux->index; l; l = l->next, i++) {
1560     GstFlvMuxIndexEntry *entry = l->data;
1561
1562     if (i % index_skip != 0)
1563       continue;
1564     GST_WRITE_UINT8 (data, 0);  /* numeric (aka double) */
1565     GST_WRITE_DOUBLE_BE (data + 1, entry->time);
1566     data += 9;
1567   }
1568
1569   GST_WRITE_UINT16_BE (data, 13);       /* second string key: 'filepositions' */
1570   memcpy (data + 2, "filepositions", 13);
1571   GST_WRITE_UINT8 (data + 15, 10);      /* strict array */
1572   GST_WRITE_UINT32_BE (data + 16, index_len);
1573   data += 20;
1574
1575   /* the keyframes' file positions */
1576   for (i = 0, l = mux->index; l; l = l->next, i++) {
1577     GstFlvMuxIndexEntry *entry = l->data;
1578
1579     if (i % index_skip != 0)
1580       continue;
1581     GST_WRITE_UINT8 (data, 0);
1582     GST_WRITE_DOUBLE_BE (data + 1, entry->position);
1583     data += 9;
1584   }
1585
1586   GST_WRITE_UINT24_BE (data, 9);        /* finish the ECMA array */
1587
1588   /* If there is space left in the prefilled area, reinsert the filler.
1589      There is at least 18  bytes free, so it will always fit. */
1590   if (index_len < MAX_INDEX_ENTRIES) {
1591     GstBuffer *tmp;
1592     guint8 *data;
1593     guint32 remaining_filler_size;
1594
1595     _gst_buffer_new_and_alloc (14, &tmp, &data);
1596     GST_WRITE_UINT16_BE (data, 9);
1597     memcpy (data + 2, "gstfiller", 9);
1598     GST_WRITE_UINT8 (data + 11, 2);     /* string */
1599
1600     /* There is 18 bytes per remaining index entry minus what is used for
1601      * the'gstfiller' key. The rest is already filled with spaces, so just need
1602      * to update length. */
1603     remaining_filler_size = (MAX_INDEX_ENTRIES - index_len) * 18 - 14;
1604     GST_DEBUG_OBJECT (mux, "Remaining filler size is %d bytes",
1605         remaining_filler_size);
1606     GST_WRITE_UINT16_BE (data + 12, remaining_filler_size);
1607     index = gst_buffer_append (index, tmp);
1608   }
1609
1610   rewrite = gst_buffer_append (rewrite, index);
1611
1612   return gst_flv_mux_push (mux, rewrite);
1613 }
1614
1615 static GstFlvMuxPad *
1616 gst_flv_mux_find_best_pad (GstAggregator * aggregator, GstClockTime * ts)
1617 {
1618   GstAggregatorPad *apad;
1619   GstFlvMuxPad *pad, *best = NULL;
1620   GList *l;
1621   GstBuffer *buffer;
1622   GstClockTime best_ts = GST_CLOCK_TIME_NONE;
1623
1624   for (l = GST_ELEMENT_CAST (aggregator)->sinkpads; l; l = l->next) {
1625     apad = GST_AGGREGATOR_PAD (l->data);
1626     pad = GST_FLV_MUX_PAD (l->data);
1627     buffer = gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (pad));
1628     if (!buffer)
1629       continue;
1630     if (best_ts == GST_CLOCK_TIME_NONE) {
1631       best = pad;
1632       best_ts = gst_flv_mux_segment_to_running_time (&apad->segment,
1633           GST_BUFFER_DTS_OR_PTS (buffer));
1634     } else if (GST_BUFFER_DTS_OR_PTS (buffer) != GST_CLOCK_TIME_NONE) {
1635       gint64 t = gst_flv_mux_segment_to_running_time (&apad->segment,
1636           GST_BUFFER_DTS_OR_PTS (buffer));
1637       if (t < best_ts) {
1638         best = pad;
1639         best_ts = t;
1640       }
1641     }
1642     gst_buffer_unref (buffer);
1643   }
1644   GST_DEBUG_OBJECT (aggregator,
1645       "Best pad found with %" GST_TIME_FORMAT ": %" GST_PTR_FORMAT,
1646       GST_TIME_ARGS (best_ts), best);
1647   if (ts)
1648     *ts = best_ts;
1649   return best;
1650 }
1651
1652 static GstFlowReturn
1653 gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout)
1654 {
1655   GstFlvMux *mux = GST_FLV_MUX (aggregator);
1656   GstFlvMuxPad *best;
1657   gint64 best_time = GST_CLOCK_STIME_NONE;
1658   GstFlowReturn ret;
1659   GstClockTime ts;
1660   GstBuffer *buffer = NULL;
1661
1662   if (mux->state == GST_FLV_MUX_STATE_HEADER) {
1663     if (GST_ELEMENT_CAST (mux)->sinkpads == NULL) {
1664       GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
1665           ("No input streams configured"));
1666       return GST_FLOW_ERROR;
1667     }
1668
1669     ret = gst_flv_mux_write_header (mux);
1670     if (ret != GST_FLOW_OK)
1671       return ret;
1672     mux->state = GST_FLV_MUX_STATE_DATA;
1673
1674     best = gst_flv_mux_find_best_pad (aggregator, &ts);
1675     if (best && GST_CLOCK_STIME_IS_VALID (ts))
1676       mux->first_timestamp = ts;
1677     else
1678       mux->first_timestamp = 0;
1679   } else {
1680     best = gst_flv_mux_find_best_pad (aggregator, &ts);
1681   }
1682
1683   if (mux->new_tags) {
1684     GstBuffer *buf = gst_flv_mux_create_metadata (mux, FALSE);
1685     if (buf)
1686       gst_flv_mux_push (mux, buf);
1687     mux->new_tags = FALSE;
1688   }
1689
1690   if (best) {
1691     buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
1692     g_assert (buffer);
1693     best->dts =
1694         gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
1695         (best)->segment, GST_BUFFER_DTS_OR_PTS (buffer));
1696
1697     if (GST_CLOCK_STIME_IS_VALID (best->dts))
1698       best_time = best->dts - mux->first_timestamp;
1699
1700     if (GST_BUFFER_PTS_IS_VALID (buffer))
1701       best->pts =
1702           gst_flv_mux_segment_to_running_time (&GST_AGGREGATOR_PAD
1703           (best)->segment, GST_BUFFER_PTS (buffer));
1704     else
1705       best->pts = best->dts;
1706
1707     GST_LOG_OBJECT (best, "got buffer PTS %" GST_TIME_FORMAT " DTS %"
1708         GST_STIME_FORMAT, GST_TIME_ARGS (best->pts),
1709         GST_STIME_ARGS (best->dts));
1710   } else {
1711     best_time = GST_CLOCK_STIME_NONE;
1712   }
1713
1714   /* The FLV timestamp is an int32 field. For non-live streams error out if a
1715      bigger timestamp is seen, for live the timestamp will get wrapped in
1716      gst_flv_mux_buffer_to_tag */
1717   if (!mux->streamable && (GST_CLOCK_STIME_IS_VALID (best_time))
1718       && best_time / GST_MSECOND > G_MAXINT32) {
1719     GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS");
1720     if (buffer) {
1721       gst_buffer_unref (buffer);
1722       buffer = NULL;
1723     }
1724     best = NULL;
1725   }
1726
1727   if (best) {
1728     return gst_flv_mux_write_buffer (mux, best, buffer);
1729   } else {
1730     if (gst_flv_mux_are_all_pads_eos (mux)) {
1731       gst_flv_mux_write_eos (mux);
1732       gst_flv_mux_rewrite_header (mux);
1733       return GST_FLOW_EOS;
1734     }
1735     return GST_FLOW_OK;
1736   }
1737 }
1738
1739 static void
1740 gst_flv_mux_get_property (GObject * object,
1741     guint prop_id, GValue * value, GParamSpec * pspec)
1742 {
1743   GstFlvMux *mux = GST_FLV_MUX (object);
1744
1745   switch (prop_id) {
1746     case PROP_STREAMABLE:
1747       g_value_set_boolean (value, mux->streamable);
1748       break;
1749     case PROP_METADATACREATOR:
1750       g_value_set_string (value, mux->metadatacreator);
1751       break;
1752     default:
1753       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1754       break;
1755   }
1756 }
1757
1758 static void
1759 gst_flv_mux_set_property (GObject * object,
1760     guint prop_id, const GValue * value, GParamSpec * pspec)
1761 {
1762   GstFlvMux *mux = GST_FLV_MUX (object);
1763
1764   switch (prop_id) {
1765     case PROP_STREAMABLE:
1766       mux->streamable = g_value_get_boolean (value);
1767       if (mux->streamable)
1768         gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux),
1769             GST_TAG_MERGE_REPLACE);
1770       else
1771         gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (mux),
1772             GST_TAG_MERGE_KEEP);
1773       break;
1774     case PROP_METADATACREATOR:
1775       g_free (mux->metadatacreator);
1776       if (!g_value_get_string (value)) {
1777         GST_WARNING_OBJECT (mux, "metadatacreator property can not be NULL");
1778         mux->metadatacreator = g_strdup (DEFAULT_METADATACREATOR);
1779       } else {
1780         mux->metadatacreator = g_value_dup_string (value);
1781       }
1782       break;
1783     default:
1784       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1785       break;
1786   }
1787 }
1788
1789 static GstClockTime
1790 gst_flv_mux_get_next_time_for_segment (GstAggregator * aggregator,
1791     const GstSegment * segment)
1792 {
1793   GstClockTime next_time;
1794
1795   GST_OBJECT_LOCK (aggregator);
1796   if (segment->position == -1 || segment->position < segment->start)
1797     next_time = segment->start;
1798   else
1799     next_time = segment->position;
1800
1801   if (segment->stop != -1 && next_time > segment->stop)
1802     next_time = segment->stop;
1803
1804   next_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, next_time);
1805   GST_OBJECT_UNLOCK (aggregator);
1806
1807   GST_DEBUG_OBJECT (aggregator, "next_time: %" GST_TIME_FORMAT,
1808       GST_TIME_ARGS (next_time));
1809   return next_time;
1810 }
1811
1812 static GstClockTime
1813 gst_flv_mux_get_next_time (GstAggregator * aggregator)
1814 {
1815   return gst_flv_mux_get_next_time_for_segment (aggregator,
1816       &GST_AGGREGATOR_PAD (aggregator->srcpad)->segment);
1817 }