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