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