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