• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-flvdemux
22  * @title: flvdemux
23  *
24  * flvdemux demuxes an FLV file into the different contained streams.
25  *
26  * ## Example launch line
27  * |[
28  * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29  * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
30  *
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "gstflvelements.h"
38 #include "gstflvdemux.h"
39 #include "gstflvmux.h"
40 
41 #include <string.h>
42 #include <stdio.h>
43 #include <gst/base/gstbytereader.h>
44 #include <gst/base/gstbytewriter.h>
45 #include <gst/pbutils/descriptions.h>
46 #include <gst/pbutils/pbutils.h>
47 #include <gst/audio/audio.h>
48 #include <gst/video/video.h>
49 #include <gst/tag/tag.h>
50 
51 GST_DEBUG_CATEGORY_EXTERN (flvdemux_debug);
52 #define GST_CAT_DEFAULT flvdemux_debug
53 
54 /* FIXME: don't rely on own GstIndex */
55 #include "gstindex.c"
56 #include "gstmemindex.c"
57 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
58 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
59 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
60 
61 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
62     GST_PAD_SINK,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS ("video/x-flv")
65     );
66 
67 static GstStaticPadTemplate audio_src_template =
68     GST_STATIC_PAD_TEMPLATE ("audio",
69     GST_PAD_SRC,
70     GST_PAD_SOMETIMES,
71     GST_STATIC_CAPS
72     ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
73         "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
74         "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
75         "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
76         "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
77         "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) 8000; "
78         "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) 8000; "
79         "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
80     );
81 
82 static GstStaticPadTemplate video_src_template =
83     GST_STATIC_PAD_TEMPLATE ("video",
84     GST_PAD_SRC,
85     GST_PAD_SOMETIMES,
86     GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
87         "video/x-flash-screen; "
88         "video/x-vp6-flash; " "video/x-vp6-alpha; "
89         "video/x-h264, stream-format=avc;")
90     );
91 
92 #define gst_flv_demux_parent_class parent_class
93 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
94 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (flvdemux, "flvdemux",
95     GST_RANK_PRIMARY, GST_TYPE_FLV_DEMUX, flv_element_init (plugin));
96 
97 /* 9 bytes of header + 4 bytes of first previous tag size */
98 #define FLV_HEADER_SIZE 13
99 /* 1 byte of tag type + 3 bytes of tag data size */
100 #define FLV_TAG_TYPE_SIZE 4
101 
102 /* two seconds - consider dts are resynced to another base if this different */
103 #define RESYNC_THRESHOLD 2000
104 
105 /* how much stream time to wait for audio tags to appear after we have video, or vice versa */
106 #define NO_MORE_PADS_THRESHOLD (6 * GST_SECOND)
107 
108 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
109     GstEvent * event);
110 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
111     GstEvent * event, gboolean seeking);
112 
113 static gboolean gst_flv_demux_sink_query (GstPad * pad, GstObject * parent,
114     GstQuery * query);
115 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
116     GstQuery * query);
117 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
118     GstEvent * event);
119 
120 static GstIndex *gst_flv_demux_get_index (GstElement * element);
121 
122 static void gst_flv_demux_push_tags (GstFlvDemux * demux);
123 
124 static void
gst_flv_demux_parse_and_add_index_entry(GstFlvDemux * demux,GstClockTime ts,guint64 pos,gboolean keyframe)125 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
126     guint64 pos, gboolean keyframe)
127 {
128   GstIndexAssociation associations[2];
129   GstIndex *index;
130   GstIndexEntry *entry;
131 
132   GST_LOG_OBJECT (demux,
133       "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
134       keyframe, GST_TIME_ARGS (ts), pos);
135 
136   /* if upstream is not seekable there is no point in building an index */
137   if (!demux->upstream_seekable)
138     return;
139 
140   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
141 
142   if (!index)
143     return;
144 
145   /* entry may already have been added before, avoid adding indefinitely */
146   entry = gst_index_get_assoc_entry (index, demux->index_id,
147       GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
148 
149   if (entry) {
150 #ifndef GST_DISABLE_GST_DEBUG
151     gint64 time = 0;
152     gboolean key;
153 
154     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
155     key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
156     GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
157         ", keyframe %d", GST_TIME_ARGS (time), key);
158     /* there is not really a way to delete the existing one */
159     if (time != ts || key != ! !keyframe)
160       GST_DEBUG_OBJECT (demux, "metadata mismatch");
161 #endif
162     gst_object_unref (index);
163     return;
164   }
165 
166   associations[0].format = GST_FORMAT_TIME;
167   associations[0].value = ts;
168   associations[1].format = GST_FORMAT_BYTES;
169   associations[1].value = pos;
170 
171   gst_index_add_associationv (index, demux->index_id,
172       (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
173       GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
174       (const GstIndexAssociation *) &associations);
175 
176   if (pos > demux->index_max_pos)
177     demux->index_max_pos = pos;
178   if (ts > demux->index_max_time)
179     demux->index_max_time = ts;
180 
181   gst_object_unref (index);
182 }
183 
184 static gchar *
FLV_GET_STRING(GstByteReader * reader)185 FLV_GET_STRING (GstByteReader * reader)
186 {
187   guint16 string_size = 0;
188   gchar *string = NULL;
189   const guint8 *str = NULL;
190 
191   g_return_val_if_fail (reader != NULL, NULL);
192 
193   if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
194     return NULL;
195 
196   if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
197     return NULL;
198 
199   string = g_try_malloc0 (string_size + 1);
200   if (G_UNLIKELY (!string)) {
201     return NULL;
202   }
203 
204   if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
205     g_free (string);
206     return NULL;
207   }
208 
209   memcpy (string, str, string_size);
210   /* Check utf-8 validity if it's not an empty string */
211   if (string[0] && !g_utf8_validate (string, string_size, NULL)) {
212     g_free (string);
213     return NULL;
214   }
215 
216   return string;
217 }
218 
219 static void
gst_flv_demux_check_seekability(GstFlvDemux * demux)220 gst_flv_demux_check_seekability (GstFlvDemux * demux)
221 {
222   GstQuery *query;
223   gint64 start = -1, stop = -1;
224 
225   demux->upstream_seekable = FALSE;
226 
227   query = gst_query_new_seeking (GST_FORMAT_BYTES);
228   if (!gst_pad_peer_query (demux->sinkpad, query)) {
229     GST_DEBUG_OBJECT (demux, "seeking query failed");
230     gst_query_unref (query);
231     return;
232   }
233 
234   gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
235       &start, &stop);
236 
237   gst_query_unref (query);
238 
239   /* try harder to query upstream size if we didn't get it the first time */
240   if (demux->upstream_seekable && stop == -1) {
241     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
242     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
243   }
244 
245   /* if upstream doesn't know the size, it's likely that it's not seekable in
246    * practice even if it technically may be seekable */
247   if (demux->upstream_seekable && (start != 0 || stop <= start)) {
248     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
249     demux->upstream_seekable = FALSE;
250   }
251 
252   GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
253 }
254 
255 static GstDateTime *
parse_flv_demux_parse_date_string(const gchar * s)256 parse_flv_demux_parse_date_string (const gchar * s)
257 {
258   static const gchar months[12][4] = {
259     "Jan", "Feb", "Mar", "Apr",
260     "May", "Jun", "Jul", "Aug",
261     "Sep", "Oct", "Nov", "Dec"
262   };
263   GstDateTime *dt = NULL;
264   gchar **tokens;
265   guint64 d;
266   gchar *endptr, *stripped;
267   gint i, hh, mm, ss;
268   gint year = -1, month = -1, day = -1;
269   gint hour = -1, minute = -1, seconds = -1;
270 
271   stripped = g_strstrip (g_strdup (s));
272 
273   /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
274   tokens = g_strsplit (stripped, " ", -1);
275 
276   g_free (stripped);
277 
278   if (g_strv_length (tokens) != 5)
279     goto out;
280 
281   /* year */
282   d = g_ascii_strtoull (tokens[4], &endptr, 10);
283   if (d == 0 && *endptr != '\0')
284     goto out;
285 
286   year = d;
287 
288   /* month */
289   if (strlen (tokens[1]) != 3)
290     goto out;
291   for (i = 0; i < 12; i++) {
292     if (!strcmp (tokens[1], months[i])) {
293       break;
294     }
295   }
296   if (i == 12)
297     goto out;
298 
299   month = i + 1;
300 
301   /* day */
302   d = g_ascii_strtoull (tokens[2], &endptr, 10);
303   if (d == 0 && *endptr != '\0')
304     goto out;
305 
306   day = d;
307 
308   /* time */
309   hh = mm = ss = 0;
310   if (sscanf (tokens[3], "%d:%d:%d", &hh, &mm, &ss) < 2)
311     goto out;
312   if (hh >= 0 && hh < 24 && mm >= 0 && mm < 60 && ss >= 0 && ss < 60) {
313     hour = hh;
314     minute = mm;
315     seconds = ss;
316   }
317 
318 out:
319 
320   if (tokens)
321     g_strfreev (tokens);
322 
323   if (year > 0)
324     dt = gst_date_time_new (0.0, year, month, day, hour, minute, seconds);
325 
326   return dt;
327 }
328 
329 static gboolean
gst_flv_demux_parse_metadata_item(GstFlvDemux * demux,GstByteReader * reader,gboolean * end_marker)330 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
331     gboolean * end_marker)
332 {
333   gchar *tag_name = NULL;
334   guint8 tag_type = 0;
335 
336   /* Initialize the end_marker flag to FALSE */
337   *end_marker = FALSE;
338 
339   /* Name of the tag */
340   tag_name = FLV_GET_STRING (reader);
341   if (G_UNLIKELY (!tag_name)) {
342     GST_WARNING_OBJECT (demux, "failed reading tag name");
343     return FALSE;
344   }
345 
346   /* What kind of object is that */
347   if (!gst_byte_reader_get_uint8 (reader, &tag_type))
348     goto error;
349 
350   GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
351 
352   switch (tag_type) {
353     case 0:                    /* Double */
354     {                           /* Use a union to read the uint64 and then as a double */
355       gdouble d = 0;
356 
357       if (!gst_byte_reader_get_float64_be (reader, &d))
358         goto error;
359 
360       GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
361 
362       if (!strcmp (tag_name, "duration")) {
363         demux->duration = d * GST_SECOND;
364 
365         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
366             GST_TAG_DURATION, demux->duration, NULL);
367       } else if (!strcmp (tag_name, "AspectRatioX")) {
368         demux->par_x = d;
369         demux->got_par = TRUE;
370       } else if (!strcmp (tag_name, "AspectRatioY")) {
371         demux->par_y = d;
372         demux->got_par = TRUE;
373       } else if (!strcmp (tag_name, "width")) {
374         demux->w = d;
375       } else if (!strcmp (tag_name, "height")) {
376         demux->h = d;
377       } else if (!strcmp (tag_name, "framerate")) {
378         demux->framerate = d;
379       } else if (!strcmp (tag_name, "audiodatarate")) {
380         demux->audio_bitrate = (guint) (d * 1024);
381         gst_tag_list_add (demux->audio_tags, GST_TAG_MERGE_REPLACE,
382             GST_TAG_NOMINAL_BITRATE, demux->audio_bitrate, NULL);
383       } else if (!strcmp (tag_name, "videodatarate")) {
384         demux->video_bitrate = (guint) (d * 1024);
385         gst_tag_list_add (demux->video_tags, GST_TAG_MERGE_REPLACE,
386             GST_TAG_NOMINAL_BITRATE, demux->video_bitrate, NULL);
387       } else {
388         GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
389       }
390 
391       break;
392     }
393     case 1:                    /* Boolean */
394     {
395       guint8 b = 0;
396 
397       if (!gst_byte_reader_get_uint8 (reader, &b))
398         goto error;
399 
400       GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
401 
402       GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
403 
404       break;
405     }
406     case 2:                    /* String */
407     {
408       gchar *s = NULL;
409 
410       s = FLV_GET_STRING (reader);
411       if (s == NULL)
412         goto error;
413       if (!strcmp (s, "")) {
414         /* Not strictly an error, just an empty string */
415         g_free (s);
416         break;
417       }
418 
419       GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
420 
421       if (!strcmp (tag_name, "creationdate")) {
422         GstDateTime *dt;
423 
424         dt = parse_flv_demux_parse_date_string (s);
425         if (dt == NULL) {
426           GST_DEBUG_OBJECT (demux, "Failed to parse '%s' into datetime", s);
427         } else {
428           gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
429               GST_TAG_DATE_TIME, dt, NULL);
430           gst_date_time_unref (dt);
431         }
432       } else if (!strcmp (tag_name, "creator")) {
433         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
434             GST_TAG_ARTIST, s, NULL);
435       } else if (!strcmp (tag_name, "title")) {
436         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
437             GST_TAG_TITLE, s, NULL);
438       } else if (!strcmp (tag_name, "metadatacreator")
439           || !strcmp (tag_name, "encoder")) {
440         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
441             GST_TAG_ENCODER, s, NULL);
442       } else {
443         GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
444       }
445 
446       g_free (s);
447 
448       break;
449     }
450     case 3:                    /* Object */
451     {
452       gboolean end_of_object_marker = FALSE;
453 
454       while (!end_of_object_marker) {
455         gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
456             &end_of_object_marker);
457 
458         if (G_UNLIKELY (!ok)) {
459           GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
460           goto error;
461         }
462       }
463 
464       break;
465     }
466     case 8:                    /* ECMA array */
467     {
468       guint32 nb_elems = 0;
469       gboolean end_of_object_marker = FALSE;
470 
471       if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
472         goto error;
473 
474       GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
475           nb_elems);
476 
477       while (!end_of_object_marker) {
478         gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
479             &end_of_object_marker);
480 
481         if (G_UNLIKELY (!ok)) {
482           GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
483           goto error;
484         }
485       }
486 
487       break;
488     }
489     case 9:                    /* End marker */
490     {
491       GST_DEBUG_OBJECT (demux, "end marker ?");
492       if (tag_name[0] == '\0') {
493 
494         GST_DEBUG_OBJECT (demux, "end marker detected");
495 
496         *end_marker = TRUE;
497       }
498 
499       break;
500     }
501     case 10:                   /* Array */
502     {
503       guint32 nb_elems = 0;
504 
505       if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
506         goto error;
507 
508       GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
509 
510       if (!strcmp (tag_name, "times")) {
511         if (demux->times) {
512           g_array_free (demux->times, TRUE);
513         }
514         demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
515       } else if (!strcmp (tag_name, "filepositions")) {
516         if (demux->filepositions) {
517           g_array_free (demux->filepositions, TRUE);
518         }
519         demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
520       }
521 
522       while (nb_elems--) {
523         guint8 elem_type = 0;
524 
525         if (!gst_byte_reader_get_uint8 (reader, &elem_type))
526           goto error;
527 
528         switch (elem_type) {
529           case 0:
530           {
531             gdouble d;
532 
533             if (!gst_byte_reader_get_float64_be (reader, &d))
534               goto error;
535 
536             GST_DEBUG_OBJECT (demux, "element is a double %f", d);
537 
538             if (!strcmp (tag_name, "times") && demux->times) {
539               g_array_append_val (demux->times, d);
540             } else if (!strcmp (tag_name, "filepositions") &&
541                 demux->filepositions) {
542               g_array_append_val (demux->filepositions, d);
543             }
544             break;
545           }
546           default:
547             GST_WARNING_OBJECT (demux, "unsupported array element type %d",
548                 elem_type);
549         }
550       }
551 
552       break;
553     }
554     case 11:                   /* Date */
555     {
556       gdouble d = 0;
557       gint16 i = 0;
558 
559       if (!gst_byte_reader_get_float64_be (reader, &d))
560         goto error;
561 
562       if (!gst_byte_reader_get_int16_be (reader, &i))
563         goto error;
564 
565       GST_DEBUG_OBJECT (demux,
566           "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
567 
568       GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
569 
570       break;
571     }
572     default:
573       GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
574   }
575 
576   g_free (tag_name);
577 
578   return TRUE;
579 
580 error:
581   g_free (tag_name);
582 
583   return FALSE;
584 }
585 
586 static void
gst_flv_demux_clear_tags(GstFlvDemux * demux)587 gst_flv_demux_clear_tags (GstFlvDemux * demux)
588 {
589   GST_DEBUG_OBJECT (demux, "clearing taglist");
590 
591   if (demux->taglist) {
592     gst_tag_list_unref (demux->taglist);
593   }
594   demux->taglist = gst_tag_list_new_empty ();
595   gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
596 
597   if (demux->audio_tags) {
598     gst_tag_list_unref (demux->audio_tags);
599   }
600   demux->audio_tags = gst_tag_list_new_empty ();
601 
602   if (demux->video_tags) {
603     gst_tag_list_unref (demux->video_tags);
604   }
605   demux->video_tags = gst_tag_list_new_empty ();
606 }
607 
608 static GstFlowReturn
gst_flv_demux_parse_tag_script(GstFlvDemux * demux,GstBuffer * buffer)609 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
610 {
611   GstFlowReturn ret = GST_FLOW_OK;
612   GstByteReader reader;
613   guint8 type = 0;
614   GstMapInfo map;
615 
616   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
617 
618   gst_buffer_map (buffer, &map, GST_MAP_READ);
619   gst_byte_reader_init (&reader, map.data, map.size);
620 
621   gst_byte_reader_skip_unchecked (&reader, 7);
622 
623   GST_LOG_OBJECT (demux, "parsing a script tag");
624 
625   if (!gst_byte_reader_get_uint8 (&reader, &type))
626     goto cleanup;
627 
628   /* Must be string */
629   if (type == 2) {
630     gchar *function_name;
631     guint i;
632 
633     function_name = FLV_GET_STRING (&reader);
634 
635     GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
636 
637     if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
638       gboolean end_marker = FALSE;
639       GST_DEBUG_OBJECT (demux, "we have a metadata script object");
640 
641       gst_flv_demux_clear_tags (demux);
642 
643       if (!gst_byte_reader_get_uint8 (&reader, &type)) {
644         g_free (function_name);
645         goto cleanup;
646       }
647 
648       switch (type) {
649         case 8:
650         {
651           guint32 nb_elems = 0;
652 
653           /* ECMA array */
654           if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
655             g_free (function_name);
656             goto cleanup;
657           }
658 
659           /* The number of elements is just a hint, some files have
660              nb_elements == 0 and actually contain items. */
661           GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
662               nb_elems);
663         }
664           /* fallthrough to read data */
665         case 3:
666         {
667           /* Object */
668           while (!end_marker) {
669             gboolean ok =
670                 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
671 
672             if (G_UNLIKELY (!ok)) {
673               GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
674               break;
675             }
676           }
677         }
678           break;
679         default:
680           GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
681           g_free (function_name);
682           goto cleanup;
683       }
684 
685       gst_flv_demux_push_tags (demux);
686     }
687 
688     g_free (function_name);
689 
690     if (demux->times && demux->filepositions) {
691       guint num;
692 
693       /* If an index was found, insert associations */
694       num = MIN (demux->times->len, demux->filepositions->len);
695       for (i = 0; i < num; i++) {
696         guint64 time, fileposition;
697 
698         time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
699         fileposition = g_array_index (demux->filepositions, gdouble, i);
700         gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
701             TRUE);
702       }
703       demux->indexed = TRUE;
704     }
705   }
706 
707 cleanup:
708   gst_buffer_unmap (buffer, &map);
709 
710   return ret;
711 }
712 
713 static gboolean
have_group_id(GstFlvDemux * demux)714 have_group_id (GstFlvDemux * demux)
715 {
716   GstEvent *event;
717 
718   event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
719   if (event) {
720     if (gst_event_parse_group_id (event, &demux->group_id))
721       demux->have_group_id = TRUE;
722     else
723       demux->have_group_id = FALSE;
724     gst_event_unref (event);
725   } else if (!demux->have_group_id) {
726     demux->have_group_id = TRUE;
727     demux->group_id = gst_util_group_id_next ();
728   }
729 
730   return demux->have_group_id;
731 }
732 
733 static gboolean
gst_flv_demux_audio_negotiate(GstFlvDemux * demux,guint32 codec_tag,guint32 rate,guint32 channels,guint32 width)734 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
735     guint32 rate, guint32 channels, guint32 width)
736 {
737   GstCaps *caps = NULL, *old_caps;
738   gboolean ret = FALSE;
739   guint adjusted_rate = rate;
740   guint adjusted_channels = channels;
741   GstEvent *event;
742   gchar *stream_id;
743 
744   switch (codec_tag) {
745     case 1:
746       caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
747           "swf", NULL);
748       break;
749     case 2:
750     case 14:
751       caps = gst_caps_new_simple ("audio/mpeg",
752           "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
753           "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
754       break;
755     case 0:
756     case 3:
757     {
758       GstAudioFormat format;
759 
760       /* Assuming little endian for 0 (aka endianness of the
761        * system on which the file was created) as most people
762        * are probably using little endian machines */
763       format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
764           G_LITTLE_ENDIAN, width, width);
765 
766       caps = gst_caps_new_simple ("audio/x-raw",
767           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
768           "layout", G_TYPE_STRING, "interleaved", NULL);
769       break;
770     }
771     case 4:
772     case 5:
773     case 6:
774       caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
775       break;
776     case 10:
777     {
778       GstMapInfo map;
779       if (!demux->audio_codec_data) {
780         GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
781         ret = TRUE;
782         goto done;
783       }
784 
785       gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
786 
787       /* use codec-data to extract and verify samplerate */
788       if (map.size >= 2) {
789         gint freq_index;
790 
791         freq_index = GST_READ_UINT16_BE (map.data);
792         freq_index = (freq_index & 0x0780) >> 7;
793         adjusted_rate =
794             gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
795 
796         if (adjusted_rate && (rate != adjusted_rate)) {
797           GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
798               adjusted_rate);
799         } else {
800           adjusted_rate = rate;
801         }
802 
803         adjusted_channels =
804             gst_codec_utils_aac_get_channels (map.data, map.size);
805 
806         if (adjusted_channels && (channels != adjusted_channels)) {
807           GST_LOG_OBJECT (demux, "Ajusting AAC channels %d -> %d", channels,
808               adjusted_channels);
809         } else {
810           adjusted_channels = channels;
811         }
812       }
813       gst_buffer_unmap (demux->audio_codec_data, &map);
814 
815       caps = gst_caps_new_simple ("audio/mpeg",
816           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
817           "stream-format", G_TYPE_STRING, "raw", NULL);
818       break;
819     }
820     case 7:
821       caps = gst_caps_new_empty_simple ("audio/x-alaw");
822       break;
823     case 8:
824       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
825       break;
826     case 11:
827     {
828       GValue streamheader = G_VALUE_INIT;
829       GValue value = G_VALUE_INIT;
830       GstByteWriter w;
831       GstStructure *structure;
832       GstBuffer *buf;
833       GstTagList *tags;
834 
835       caps = gst_caps_new_empty_simple ("audio/x-speex");
836       structure = gst_caps_get_structure (caps, 0);
837 
838       GST_DEBUG_OBJECT (demux, "generating speex header");
839 
840       /* Speex decoder expects streamheader to be { [header], [comment] } */
841       g_value_init (&streamheader, GST_TYPE_ARRAY);
842 
843       /* header part */
844       gst_byte_writer_init_with_size (&w, 80, TRUE);
845       gst_byte_writer_put_data (&w, (guint8 *) "Speex   ", 8);
846       gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
847       gst_byte_writer_fill (&w, 0, 13);
848       gst_byte_writer_put_uint32_le (&w, 1);    /* version */
849       gst_byte_writer_put_uint32_le (&w, 80);   /* header_size */
850       gst_byte_writer_put_uint32_le (&w, 16000);        /* rate */
851       gst_byte_writer_put_uint32_le (&w, 1);    /* mode: Wideband */
852       gst_byte_writer_put_uint32_le (&w, 4);    /* mode_bitstream_version */
853       gst_byte_writer_put_uint32_le (&w, 1);    /* nb_channels: 1 */
854       gst_byte_writer_put_uint32_le (&w, -1);   /* bitrate */
855       gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
856       gst_byte_writer_put_uint32_le (&w, 0);    /* VBR */
857       gst_byte_writer_put_uint32_le (&w, 1);    /* frames_per_packet */
858       gst_byte_writer_put_uint32_le (&w, 0);    /* extra_headers */
859       gst_byte_writer_put_uint32_le (&w, 0);    /* reserved1 */
860       gst_byte_writer_put_uint32_le (&w, 0);    /* reserved2 */
861       g_assert (gst_byte_writer_get_size (&w) == 80);
862 
863       g_value_init (&value, GST_TYPE_BUFFER);
864       g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
865       gst_value_array_append_value (&streamheader, &value);
866       g_value_unset (&value);
867 
868       /* comment part */
869       g_value_init (&value, GST_TYPE_BUFFER);
870       tags = gst_tag_list_new_empty ();
871       buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
872       gst_tag_list_unref (tags);
873       g_value_take_boxed (&value, buf);
874       gst_value_array_append_value (&streamheader, &value);
875       g_value_unset (&value);
876 
877       gst_structure_take_value (structure, "streamheader", &streamheader);
878 
879       channels = 1;
880       adjusted_rate = 16000;
881       break;
882     }
883     default:
884       GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
885       break;
886   }
887 
888   if (G_UNLIKELY (!caps)) {
889     GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
890     goto beach;
891   }
892 
893   gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
894       "channels", G_TYPE_INT, adjusted_channels, NULL);
895 
896   if (demux->audio_codec_data) {
897     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
898         demux->audio_codec_data, NULL);
899   }
900 
901   old_caps = gst_pad_get_current_caps (demux->audio_pad);
902   if (!old_caps) {
903     stream_id =
904         gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
905         "audio");
906 
907     event = gst_event_new_stream_start (stream_id);
908     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
909       gst_event_set_seqnum (event, demux->segment_seqnum);
910     if (have_group_id (demux))
911       gst_event_set_group_id (event, demux->group_id);
912     gst_pad_push_event (demux->audio_pad, event);
913     g_free (stream_id);
914   }
915   if (!old_caps || !gst_caps_is_equal (old_caps, caps))
916     ret = gst_pad_set_caps (demux->audio_pad, caps);
917   else
918     ret = TRUE;
919 
920   if (old_caps)
921     gst_caps_unref (old_caps);
922 
923 done:
924   if (G_LIKELY (ret)) {
925     /* Store the caps we got from tags */
926     demux->audio_codec_tag = codec_tag;
927     demux->rate = rate;
928     demux->channels = channels;
929     demux->width = width;
930 
931     if (caps) {
932       GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
933           GST_PTR_FORMAT, caps);
934 
935       gst_flv_demux_push_tags (demux);
936     } else {
937       GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
938     }
939   } else {
940     GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
941         GST_PTR_FORMAT, caps);
942   }
943 
944   if (caps)
945     gst_caps_unref (caps);
946 
947 beach:
948   return ret;
949 }
950 
951 static gboolean
gst_flv_demux_push_src_event(GstFlvDemux * demux,GstEvent * event)952 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
953 {
954   gboolean ret = TRUE;
955 
956   if (demux->audio_pad)
957     ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
958 
959   if (demux->video_pad)
960     ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
961 
962   gst_event_unref (event);
963 
964   return ret;
965 }
966 
967 static void
gst_flv_demux_add_codec_tag(GstFlvDemux * demux,const gchar * tag,GstPad * pad)968 gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
969     GstPad * pad)
970 {
971   if (pad) {
972     GstCaps *caps = gst_pad_get_current_caps (pad);
973 
974     if (caps) {
975       gchar *codec_name = gst_pb_utils_get_codec_description (caps);
976 
977       if (codec_name) {
978         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
979             tag, codec_name, NULL);
980         g_free (codec_name);
981       }
982 
983       gst_caps_unref (caps);
984     }
985   }
986 }
987 
988 static void
gst_flv_demux_push_tags(GstFlvDemux * demux)989 gst_flv_demux_push_tags (GstFlvDemux * demux)
990 {
991   GstEvent *tag_event;
992 
993   gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
994   gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
995 
996   GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
997 
998   tag_event = gst_event_new_tag (gst_tag_list_copy (demux->taglist));
999   if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1000     gst_event_set_seqnum (tag_event, demux->segment_seqnum);
1001   gst_flv_demux_push_src_event (demux, tag_event);
1002 
1003   if (demux->audio_pad) {
1004     GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
1005         demux->audio_tags);
1006     tag_event = gst_event_new_tag (gst_tag_list_copy (demux->audio_tags));
1007     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1008       gst_event_set_seqnum (tag_event, demux->segment_seqnum);
1009     gst_pad_push_event (demux->audio_pad, tag_event);
1010   }
1011 
1012   if (demux->video_pad) {
1013     GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
1014         demux->video_tags);
1015     tag_event = gst_event_new_tag (gst_tag_list_copy (demux->video_tags));
1016     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1017       gst_event_set_seqnum (tag_event, demux->segment_seqnum);
1018     gst_pad_push_event (demux->video_pad, tag_event);
1019   }
1020 }
1021 
1022 static gboolean
gst_flv_demux_update_resync(GstFlvDemux * demux,guint32 dts,gboolean discont,guint32 * last,GstClockTime * offset)1023 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
1024     guint32 * last, GstClockTime * offset)
1025 {
1026   gboolean ret = FALSE;
1027   gint32 ddts = dts - *last;
1028   if (!discont && ddts <= -RESYNC_THRESHOLD) {
1029     /* Theoretically, we should use subtract the duration of the last buffer,
1030        but this demuxer sends no durations on buffers, not sure if it cannot
1031        know, or just does not care to calculate. */
1032     *offset -= ddts * GST_MSECOND;
1033     GST_WARNING_OBJECT (demux,
1034         "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
1035         GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
1036 
1037     ret = TRUE;
1038   }
1039   *last = dts;
1040 
1041   return ret;
1042 }
1043 
1044 static void
gst_flv_demux_sync_streams(GstFlvDemux * demux)1045 gst_flv_demux_sync_streams (GstFlvDemux * demux)
1046 {
1047   /* Check if the audio or video stream are more than 3s behind the other
1048    * stream, and if so send a gap event accordingly */
1049 
1050   if (demux->audio_pad && GST_CLOCK_TIME_IS_VALID (demux->segment.position) &&
1051       demux->last_audio_pts * GST_MSECOND + demux->audio_time_offset +
1052       3 * GST_SECOND < demux->segment.position) {
1053     GstEvent *event;
1054     guint64 start =
1055         demux->last_audio_pts * GST_MSECOND + demux->audio_time_offset;
1056     guint64 stop = demux->segment.position - 3 * GST_SECOND;
1057 
1058     GST_DEBUG_OBJECT (demux,
1059         "Synchronizing audio stream with video stream by advancing time from %"
1060         GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
1061         GST_TIME_ARGS (stop));
1062 
1063     demux->last_audio_pts = (stop - demux->audio_time_offset) / GST_MSECOND;
1064 
1065     event = gst_event_new_gap (start, stop - start);
1066     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1067       gst_event_set_seqnum (event, demux->segment_seqnum);
1068     gst_pad_push_event (demux->audio_pad, event);
1069   }
1070 
1071   if (demux->video_pad && GST_CLOCK_TIME_IS_VALID (demux->segment.position) &&
1072       demux->last_video_dts * GST_MSECOND + demux->video_time_offset +
1073       3 * GST_SECOND < demux->segment.position) {
1074     GstEvent *event;
1075     guint64 start =
1076         demux->last_video_dts * GST_MSECOND + demux->video_time_offset;
1077     guint64 stop = demux->segment.position - 3 * GST_SECOND;
1078 
1079     GST_DEBUG_OBJECT (demux,
1080         "Synchronizing video stream with audio stream by advancing time from %"
1081         GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
1082         GST_TIME_ARGS (stop));
1083 
1084     demux->last_video_dts = (stop - demux->video_time_offset) / GST_MSECOND;
1085 
1086     event = gst_event_new_gap (start, stop - start);
1087     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1088       gst_event_set_seqnum (event, demux->segment_seqnum);
1089     gst_pad_push_event (demux->video_pad, event);
1090   }
1091 }
1092 
1093 static GstFlowReturn
gst_flv_demux_parse_tag_audio(GstFlvDemux * demux,GstBuffer * buffer)1094 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
1095 {
1096   GstFlowReturn ret = GST_FLOW_OK;
1097   guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
1098   guint32 codec_data = 0, pts_ext = 0;
1099   guint8 flags = 0;
1100   GstMapInfo map;
1101   GstBuffer *outbuf;
1102   guint8 *data;
1103 
1104   GST_LOG_OBJECT (demux, "parsing an audio tag");
1105 
1106   if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
1107 #ifndef GST_DISABLE_DEBUG
1108     if (G_UNLIKELY (!demux->no_audio_warned)) {
1109       GST_WARNING_OBJECT (demux,
1110           "Signaled no-more-pads already but had no audio pad -- ignoring");
1111       demux->no_audio_warned = TRUE;
1112     }
1113 #endif
1114     return GST_FLOW_OK;
1115   }
1116 
1117   g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1118       GST_FLOW_ERROR);
1119 
1120   /* Error out on tags with too small headers */
1121   if (gst_buffer_get_size (buffer) < 11) {
1122     GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
1123         gst_buffer_get_size (buffer));
1124     return GST_FLOW_ERROR;
1125   }
1126 
1127   gst_buffer_map (buffer, &map, GST_MAP_READ);
1128   data = map.data;
1129 
1130   /* Grab information about audio tag */
1131   pts = GST_READ_UINT24_BE (data);
1132   /* read the pts extension to 32 bits integer */
1133   pts_ext = GST_READ_UINT8 (data + 3);
1134   /* Combine them */
1135   pts |= pts_ext << 24;
1136 
1137   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1138       data[2], data[3], pts);
1139 
1140   /* Skip the stream id and go directly to the flags */
1141   flags = GST_READ_UINT8 (data + 7);
1142 
1143   /* Silently skip buffers with no data */
1144   if (map.size == 11)
1145     goto beach;
1146 
1147   /* Channels */
1148   if (flags & 0x01) {
1149     channels = 2;
1150   }
1151   /* Width */
1152   if (flags & 0x02) {
1153     width = 16;
1154   }
1155   /* Sampling rate */
1156   if ((flags & 0x0C) == 0x0C) {
1157     rate = 44100;
1158   } else if ((flags & 0x0C) == 0x08) {
1159     rate = 22050;
1160   } else if ((flags & 0x0C) == 0x04) {
1161     rate = 11025;
1162   }
1163   /* Codec tag */
1164   codec_tag = flags >> 4;
1165   if (codec_tag == 10) {        /* AAC has an extra byte for packet type */
1166     codec_data = 2;
1167   } else {
1168     codec_data = 1;
1169   }
1170 
1171   /* codec tags with special rates */
1172   if (codec_tag == 5 || codec_tag == 14 || codec_tag == 7 || codec_tag == 8)
1173     rate = 8000;
1174   else if ((codec_tag == 4) || (codec_tag == 11))
1175     rate = 16000;
1176 
1177   GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
1178       "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
1179       codec_tag, flags);
1180 
1181   if (codec_tag == 10) {
1182     guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1183 
1184     switch (aac_packet_type) {
1185       case 0:
1186       {
1187         /* AudioSpecificConfig data */
1188         GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1189         if (demux->audio_codec_data) {
1190           gst_buffer_unref (demux->audio_codec_data);
1191         }
1192         demux->audio_codec_data =
1193             gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1194             7 + codec_data, demux->tag_data_size - codec_data);
1195 
1196         /* Use that buffer data in the caps */
1197         if (demux->audio_pad)
1198           gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1199               width);
1200         goto beach;
1201       }
1202       case 1:
1203         if (!demux->audio_codec_data) {
1204           GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
1205           ret = GST_FLOW_OK;
1206           goto beach;
1207         }
1208         /* AAC raw packet */
1209         GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1210         break;
1211       default:
1212         GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1213             aac_packet_type);
1214     }
1215   }
1216 
1217   /* If we don't have our audio pad created, then create it. */
1218   if (G_UNLIKELY (!demux->audio_pad)) {
1219     demux->audio_pad =
1220         gst_pad_new_from_template (gst_element_class_get_pad_template
1221         (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1222     if (G_UNLIKELY (!demux->audio_pad)) {
1223       GST_WARNING_OBJECT (demux, "failed creating audio pad");
1224       ret = GST_FLOW_ERROR;
1225       goto beach;
1226     }
1227 
1228     /* Set functions on the pad */
1229     gst_pad_set_query_function (demux->audio_pad,
1230         GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1231     gst_pad_set_event_function (demux->audio_pad,
1232         GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1233 
1234     gst_pad_use_fixed_caps (demux->audio_pad);
1235 
1236     /* Make it active */
1237     gst_pad_set_active (demux->audio_pad, TRUE);
1238 
1239     /* Negotiate caps */
1240     if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1241             width)) {
1242       gst_object_unref (demux->audio_pad);
1243       demux->audio_pad = NULL;
1244       ret = GST_FLOW_ERROR;
1245       goto beach;
1246     }
1247 #ifndef GST_DISABLE_GST_DEBUG
1248     {
1249       GstCaps *caps;
1250 
1251       caps = gst_pad_get_current_caps (demux->audio_pad);
1252       GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1253           caps);
1254       if (caps)
1255         gst_caps_unref (caps);
1256     }
1257 #endif
1258 
1259     /* We need to set caps before adding */
1260     gst_element_add_pad (GST_ELEMENT (demux),
1261         gst_object_ref (demux->audio_pad));
1262     gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1263 
1264     /* We only emit no more pads when we have audio and video. Indeed we can
1265      * not trust the FLV header to tell us if there will be only audio or
1266      * only video and we would just break discovery of some files */
1267     if (demux->audio_pad && demux->video_pad) {
1268       GST_DEBUG_OBJECT (demux, "emitting no more pads");
1269       gst_element_no_more_pads (GST_ELEMENT (demux));
1270       demux->no_more_pads = TRUE;
1271     }
1272   }
1273 
1274   /* Check if caps have changed */
1275   if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1276           codec_tag != demux->audio_codec_tag || width != demux->width)) {
1277     GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1278 
1279     gst_buffer_replace (&demux->audio_codec_data, NULL);
1280 
1281     /* Negotiate caps */
1282     if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1283             width)) {
1284       ret = GST_FLOW_ERROR;
1285       goto beach;
1286     }
1287   }
1288 
1289   /* Check if we have anything to push */
1290   if (demux->tag_data_size <= codec_data) {
1291     GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1292     goto beach;
1293   }
1294 
1295   /* Create buffer from pad */
1296   outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1297       7 + codec_data, demux->tag_data_size - codec_data);
1298 
1299   /* detect (and deem to be resyncs)  large pts gaps */
1300   if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1301           &demux->last_audio_pts, &demux->audio_time_offset)) {
1302     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1303   }
1304 
1305   /* Fill buffer with data */
1306   GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1307   GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1308   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1309   GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1310   GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1311 
1312   if (demux->duration == GST_CLOCK_TIME_NONE ||
1313       demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1314     demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1315 
1316   /* Only add audio frames to the index if we have no video,
1317    * and if the index is not yet complete */
1318   if (!demux->has_video && !demux->indexed) {
1319     gst_flv_demux_parse_and_add_index_entry (demux,
1320         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1321   }
1322 
1323   if (G_UNLIKELY (demux->audio_need_discont)) {
1324     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1325     demux->audio_need_discont = FALSE;
1326   }
1327 
1328   demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1329 
1330   /* Do we need a newsegment event ? */
1331   if (G_UNLIKELY (demux->audio_need_segment)) {
1332     if (!demux->new_seg_event) {
1333       GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1334           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1335           GST_TIME_ARGS (demux->segment.position),
1336           GST_TIME_ARGS (demux->segment.stop));
1337       demux->segment.start = demux->segment.time = demux->segment.position;
1338       demux->new_seg_event = gst_event_new_segment (&demux->segment);
1339       gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
1340     } else {
1341       GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1342     }
1343 
1344     gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1345 
1346     demux->audio_need_segment = FALSE;
1347   }
1348 
1349   GST_LOG_OBJECT (demux,
1350       "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1351       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1352       gst_buffer_get_size (outbuf),
1353       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1354       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1355 
1356   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1357     demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1358   }
1359   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1360     demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1361   }
1362 
1363   if (G_UNLIKELY (!demux->no_more_pads
1364           && (GST_CLOCK_DIFF (demux->audio_start,
1365                   GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1366     GST_DEBUG_OBJECT (demux,
1367         "Signalling no-more-pads because no video stream was found"
1368         " after 6 seconds of audio");
1369     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1370     demux->no_more_pads = TRUE;
1371   }
1372 
1373   /* Push downstream */
1374   ret = gst_pad_push (demux->audio_pad, outbuf);
1375 
1376   if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1377       demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1378       demux->segment.position > demux->segment.stop) {
1379     /* In reverse playback we can get a GST_FLOW_EOS when
1380      * we are at the end of the segment, so we just need to jump
1381      * back to the previous section. */
1382     GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1383     demux->audio_done = TRUE;
1384     ret = GST_FLOW_OK;
1385     goto beach;
1386   }
1387 
1388   ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1389       demux->audio_pad, ret);
1390 
1391   if (ret == GST_FLOW_OK) {
1392     gst_flv_demux_sync_streams (demux);
1393   }
1394 
1395 beach:
1396   gst_buffer_unmap (buffer, &map);
1397 
1398   return ret;
1399 }
1400 
1401 static gboolean
gst_flv_demux_video_negotiate(GstFlvDemux * demux,guint32 codec_tag)1402 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1403 {
1404   gboolean ret = FALSE;
1405   GstCaps *caps = NULL, *old_caps;
1406   GstEvent *event;
1407   gchar *stream_id;
1408 
1409   /* Generate caps for that pad */
1410   switch (codec_tag) {
1411     case 2:
1412       caps =
1413           gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1414           1, NULL);
1415       break;
1416     case 3:
1417       caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1418       break;
1419     case 4:
1420       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1421       break;
1422     case 5:
1423       caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1424       break;
1425     case 7:
1426       if (!demux->video_codec_data) {
1427         GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
1428         ret = TRUE;
1429         goto done;
1430       }
1431       caps =
1432           gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1433           "avc", NULL);
1434       break;
1435       /* The following two are non-standard but apparently used, see in ffmpeg
1436        * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
1437        * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
1438        */
1439     case 8:
1440       caps = gst_caps_new_empty_simple ("video/x-h263");
1441       break;
1442     case 9:
1443       caps =
1444           gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
1445           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1446       break;
1447     default:
1448       GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1449   }
1450 
1451   if (G_UNLIKELY (!caps)) {
1452     GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1453     goto beach;
1454   }
1455 
1456   if (demux->got_par) {
1457     gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1458         demux->par_x, demux->par_y, NULL);
1459   }
1460 
1461   if (G_LIKELY (demux->w)) {
1462     gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1463   }
1464 
1465   if (G_LIKELY (demux->h)) {
1466     gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1467   }
1468 
1469   if (G_LIKELY (demux->framerate)) {
1470     gint num = 0, den = 0;
1471 
1472     gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1473     GST_DEBUG_OBJECT (demux->video_pad,
1474         "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1475         num, den);
1476 
1477     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1478   }
1479 
1480   if (demux->video_codec_data) {
1481     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1482         demux->video_codec_data, NULL);
1483   }
1484 
1485   old_caps = gst_pad_get_current_caps (demux->video_pad);
1486   if (!old_caps) {
1487     stream_id =
1488         gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1489         "video");
1490     event = gst_event_new_stream_start (stream_id);
1491     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1492       gst_event_set_seqnum (event, demux->segment_seqnum);
1493     g_free (stream_id);
1494 
1495     if (have_group_id (demux))
1496       gst_event_set_group_id (event, demux->group_id);
1497     gst_pad_push_event (demux->video_pad, event);
1498   }
1499 
1500   if (!old_caps || !gst_caps_is_equal (old_caps, caps))
1501     ret = gst_pad_set_caps (demux->video_pad, caps);
1502   else
1503     ret = TRUE;
1504 
1505   if (old_caps)
1506     gst_caps_unref (old_caps);
1507 
1508 done:
1509   if (G_LIKELY (ret)) {
1510     /* Store the caps we have set */
1511     demux->video_codec_tag = codec_tag;
1512 
1513     if (caps) {
1514       GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1515           GST_PTR_FORMAT, caps);
1516 
1517       gst_flv_demux_push_tags (demux);
1518     } else {
1519       GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
1520     }
1521   } else {
1522     GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1523         GST_PTR_FORMAT, caps);
1524   }
1525 
1526   if (caps)
1527     gst_caps_unref (caps);
1528 
1529 beach:
1530   return ret;
1531 }
1532 
1533 static GstFlowReturn
gst_flv_demux_parse_tag_video(GstFlvDemux * demux,GstBuffer * buffer)1534 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1535 {
1536   GstFlowReturn ret = GST_FLOW_OK;
1537   guint32 dts = 0, codec_data = 1, dts_ext = 0;
1538   gint32 cts = 0;
1539   gboolean keyframe = FALSE;
1540   guint8 flags = 0, codec_tag = 0;
1541   GstBuffer *outbuf;
1542   GstMapInfo map;
1543   guint8 *data;
1544 
1545   g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1546       GST_FLOW_ERROR);
1547 
1548   GST_LOG_OBJECT (demux, "parsing a video tag");
1549 
1550   if G_UNLIKELY
1551     (!demux->video_pad && demux->no_more_pads) {
1552 #ifndef GST_DISABLE_DEBUG
1553     if G_UNLIKELY
1554       (!demux->no_video_warned) {
1555       GST_WARNING_OBJECT (demux,
1556           "Signaled no-more-pads already but had no video pad -- ignoring");
1557       demux->no_video_warned = TRUE;
1558       }
1559 #endif
1560     return GST_FLOW_OK;
1561     }
1562 
1563   if (gst_buffer_get_size (buffer) < 12) {
1564     GST_ERROR_OBJECT (demux, "Too small tag size");
1565     return GST_FLOW_ERROR;
1566   }
1567 
1568   gst_buffer_map (buffer, &map, GST_MAP_READ);
1569   data = map.data;
1570 
1571   /* Grab information about video tag */
1572   dts = GST_READ_UINT24_BE (data);
1573   /* read the dts extension to 32 bits integer */
1574   dts_ext = GST_READ_UINT8 (data + 3);
1575   /* Combine them */
1576   dts |= dts_ext << 24;
1577 
1578   GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1579       data[2], data[3], dts);
1580 
1581   /* Skip the stream id and go directly to the flags */
1582   flags = GST_READ_UINT8 (data + 7);
1583 
1584   /* Keyframe */
1585   if ((flags >> 4) == 1) {
1586     keyframe = TRUE;
1587   }
1588   /* Codec tag */
1589   codec_tag = flags & 0x0F;
1590   if (codec_tag == 4 || codec_tag == 5) {
1591     codec_data = 2;
1592   } else if (codec_tag == 7) {
1593     codec_data = 5;
1594 
1595     cts = GST_READ_UINT24_BE (data + 9);
1596     cts = (cts + 0xff800000) ^ 0xff800000;
1597 
1598     if (cts < 0 && ABS (cts) > dts) {
1599       GST_ERROR_OBJECT (demux, "Detected a negative composition time offset "
1600           "'%d' that would lead to negative PTS, fixing", cts);
1601       cts += ABS (cts) - dts;
1602     }
1603 
1604     GST_LOG_OBJECT (demux, "got cts %d", cts);
1605   }
1606 
1607   GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1608       "(flags %02X)", codec_tag, keyframe, flags);
1609 
1610   if (codec_tag == 7) {
1611     guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1612 
1613     switch (avc_packet_type) {
1614       case 0:
1615       {
1616         if (demux->tag_data_size < codec_data) {
1617           GST_ERROR_OBJECT (demux, "Got invalid H.264 codec, ignoring.");
1618           break;
1619         }
1620 
1621         /* AVCDecoderConfigurationRecord data */
1622         GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1623         if (demux->video_codec_data) {
1624           gst_buffer_unref (demux->video_codec_data);
1625         }
1626         demux->video_codec_data = gst_buffer_copy_region (buffer,
1627             GST_BUFFER_COPY_MEMORY, 7 + codec_data,
1628             demux->tag_data_size - codec_data);;
1629         /* Use that buffer data in the caps */
1630         if (demux->video_pad)
1631           gst_flv_demux_video_negotiate (demux, codec_tag);
1632         goto beach;
1633       }
1634       case 1:
1635         /* H.264 NALU packet */
1636         if (!demux->video_codec_data) {
1637           GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
1638           ret = GST_FLOW_OK;
1639           goto beach;
1640         }
1641         GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1642         break;
1643       default:
1644         GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1645             avc_packet_type);
1646     }
1647   }
1648 
1649   /* If we don't have our video pad created, then create it. */
1650   if (G_UNLIKELY (!demux->video_pad)) {
1651     demux->video_pad =
1652         gst_pad_new_from_template (gst_element_class_get_pad_template
1653         (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1654     if (G_UNLIKELY (!demux->video_pad)) {
1655       GST_WARNING_OBJECT (demux, "failed creating video pad");
1656       ret = GST_FLOW_ERROR;
1657       goto beach;
1658     }
1659 
1660     /* Set functions on the pad */
1661     gst_pad_set_query_function (demux->video_pad,
1662         GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1663     gst_pad_set_event_function (demux->video_pad,
1664         GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1665 
1666     gst_pad_use_fixed_caps (demux->video_pad);
1667 
1668     /* Make it active */
1669     gst_pad_set_active (demux->video_pad, TRUE);
1670 
1671     /* Needs to be active before setting caps */
1672     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1673       gst_object_unref (demux->video_pad);
1674       demux->video_pad = NULL;
1675       ret = GST_FLOW_ERROR;
1676       goto beach;
1677     }
1678 
1679     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1680      * metadata tag that would come later and trigger a caps change */
1681     demux->got_par = FALSE;
1682 
1683 #ifndef GST_DISABLE_GST_DEBUG
1684     {
1685       GstCaps *caps;
1686 
1687       caps = gst_pad_get_current_caps (demux->video_pad);
1688       GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1689           caps);
1690       if (caps)
1691         gst_caps_unref (caps);
1692     }
1693 #endif
1694 
1695     /* We need to set caps before adding */
1696     gst_element_add_pad (GST_ELEMENT (demux),
1697         gst_object_ref (demux->video_pad));
1698     gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1699 
1700     /* We only emit no more pads when we have audio and video. Indeed we can
1701      * not trust the FLV header to tell us if there will be only audio or
1702      * only video and we would just break discovery of some files */
1703     if (demux->audio_pad && demux->video_pad) {
1704       GST_DEBUG_OBJECT (demux, "emitting no more pads");
1705       gst_element_no_more_pads (GST_ELEMENT (demux));
1706       demux->no_more_pads = TRUE;
1707     }
1708   }
1709 
1710   /* Check if caps have changed */
1711   if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1712     GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1713     if (codec_tag != demux->video_codec_tag)
1714       gst_buffer_replace (&demux->video_codec_data, NULL);
1715 
1716     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1717       ret = GST_FLOW_ERROR;
1718       goto beach;
1719     }
1720 
1721     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1722      * metadata tag that would come later and trigger a caps change */
1723     demux->got_par = FALSE;
1724   }
1725 
1726   /* Check if we have anything to push */
1727   if (demux->tag_data_size <= codec_data) {
1728     GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1729     goto beach;
1730   }
1731 
1732   /* Create buffer from pad */
1733   outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1734       7 + codec_data, demux->tag_data_size - codec_data);
1735 
1736   /* detect (and deem to be resyncs)  large dts gaps */
1737   if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1738           &demux->last_video_dts, &demux->video_time_offset)) {
1739     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1740   }
1741 
1742   /* Fill buffer with data */
1743   GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1744 
1745   GST_BUFFER_PTS (outbuf) =
1746       (dts + cts) * GST_MSECOND + demux->video_time_offset;
1747   GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1748   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1749   GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1750   GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1751 
1752   if (demux->duration == GST_CLOCK_TIME_NONE ||
1753       demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1754     demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1755 
1756   if (!keyframe)
1757     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1758 
1759   if (!demux->indexed) {
1760     gst_flv_demux_parse_and_add_index_entry (demux,
1761         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1762   }
1763 
1764   if (G_UNLIKELY (demux->video_need_discont)) {
1765     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1766     demux->video_need_discont = FALSE;
1767   }
1768 
1769   demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1770 
1771   /* Do we need a newsegment event ? */
1772   if (G_UNLIKELY (demux->video_need_segment)) {
1773     if (!demux->new_seg_event) {
1774       GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1775           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1776           GST_TIME_ARGS (demux->segment.position),
1777           GST_TIME_ARGS (demux->segment.stop));
1778       demux->segment.start = demux->segment.time = demux->segment.position;
1779       demux->new_seg_event = gst_event_new_segment (&demux->segment);
1780       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
1781         gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
1782     } else {
1783       GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1784     }
1785 
1786     gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1787 
1788     demux->video_need_segment = FALSE;
1789   }
1790 
1791   GST_LOG_OBJECT (demux,
1792       "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1793       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1794       ", keyframe (%d)", gst_buffer_get_size (outbuf),
1795       GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1796       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1797       keyframe);
1798 
1799   if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1800     demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1801   }
1802   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1803     demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1804   }
1805 
1806   if (G_UNLIKELY (!demux->no_more_pads
1807           && (GST_CLOCK_DIFF (demux->video_start,
1808                   GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1809     GST_DEBUG_OBJECT (demux,
1810         "Signalling no-more-pads because no audio stream was found"
1811         " after 6 seconds of video");
1812     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1813     demux->no_more_pads = TRUE;
1814   }
1815 
1816   /* Push downstream */
1817   ret = gst_pad_push (demux->video_pad, outbuf);
1818 
1819   if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1820       demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1821       demux->segment.position > demux->segment.stop) {
1822     /* In reverse playback we can get a GST_FLOW_EOS when
1823      * we are at the end of the segment, so we just need to jump
1824      * back to the previous section. */
1825     GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1826     demux->video_done = TRUE;
1827     ret = GST_FLOW_OK;
1828     goto beach;
1829   }
1830 
1831   ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1832       demux->video_pad, ret);
1833 
1834   if (ret == GST_FLOW_OK) {
1835     gst_flv_demux_sync_streams (demux);
1836   }
1837 
1838 beach:
1839   gst_buffer_unmap (buffer, &map);
1840   return ret;
1841 }
1842 
1843 static GstClockTime
gst_flv_demux_parse_tag_timestamp(GstFlvDemux * demux,gboolean index,GstBuffer * buffer,size_t * tag_size)1844 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1845     GstBuffer * buffer, size_t * tag_size)
1846 {
1847   guint32 dts = 0, dts_ext = 0;
1848   guint32 tag_data_size;
1849   guint8 type;
1850   gboolean keyframe = TRUE;
1851   GstClockTime ret = GST_CLOCK_TIME_NONE;
1852   GstMapInfo map;
1853   guint8 *data;
1854   gsize size;
1855 
1856   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1857       GST_CLOCK_TIME_NONE);
1858 
1859   gst_buffer_map (buffer, &map, GST_MAP_READ);
1860   data = map.data;
1861   size = map.size;
1862 
1863   type = data[0];
1864 
1865   if (type != 9 && type != 8 && type != 18) {
1866     GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1867     goto exit;
1868   }
1869 
1870   if (type == 9)
1871     demux->has_video = TRUE;
1872   else if (type == 8)
1873     demux->has_audio = TRUE;
1874 
1875   tag_data_size = GST_READ_UINT24_BE (data + 1);
1876 
1877   if (size >= tag_data_size + 11 + 4) {
1878     if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1879       GST_WARNING_OBJECT (demux, "Invalid tag size");
1880       goto exit;
1881     }
1882   }
1883 
1884   if (tag_size)
1885     *tag_size = tag_data_size + 11 + 4;
1886 
1887   data += 4;
1888 
1889   GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1890       data[2], data[3]);
1891 
1892   /* Grab timestamp of tag tag */
1893   dts = GST_READ_UINT24_BE (data);
1894   /* read the dts extension to 32 bits integer */
1895   dts_ext = GST_READ_UINT8 (data + 3);
1896   /* Combine them */
1897   dts |= dts_ext << 24;
1898 
1899   if (type == 9) {
1900     data += 7;
1901 
1902     keyframe = ((data[0] >> 4) == 1);
1903   }
1904 
1905   ret = dts * GST_MSECOND;
1906   GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1907 
1908   if (index && !demux->indexed && (type == 9 || (type == 8
1909               && !demux->has_video))) {
1910     gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1911         keyframe);
1912   }
1913 
1914   if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1915     demux->duration = ret;
1916 
1917 exit:
1918   gst_buffer_unmap (buffer, &map);
1919   return ret;
1920 }
1921 
1922 static GstFlowReturn
gst_flv_demux_parse_tag_type(GstFlvDemux * demux,GstBuffer * buffer)1923 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1924 {
1925   GstFlowReturn ret = GST_FLOW_OK;
1926   guint8 tag_type = 0;
1927   GstMapInfo map;
1928 
1929   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1930 
1931   gst_buffer_map (buffer, &map, GST_MAP_READ);
1932 
1933   tag_type = map.data[0];
1934 
1935   /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1936    * 4 bytes of previous tag size */
1937   demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1938   demux->tag_size = demux->tag_data_size + 11;
1939 
1940   GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1941       demux->tag_data_size);
1942 
1943   gst_buffer_unmap (buffer, &map);
1944 
1945   switch (tag_type) {
1946     case 9:
1947       demux->state = FLV_STATE_TAG_VIDEO;
1948       demux->has_video = TRUE;
1949       break;
1950     case 8:
1951       demux->state = FLV_STATE_TAG_AUDIO;
1952       demux->has_audio = TRUE;
1953       break;
1954     case 18:
1955       demux->state = FLV_STATE_TAG_SCRIPT;
1956       break;
1957     default:
1958       GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1959       demux->state = FLV_STATE_SKIP;
1960   }
1961 
1962   return ret;
1963 }
1964 
1965 static GstFlowReturn
gst_flv_demux_parse_header(GstFlvDemux * demux,GstBuffer * buffer)1966 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1967 {
1968   GstFlowReturn ret = GST_FLOW_OK;
1969   GstMapInfo map;
1970 
1971   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1972 
1973   gst_buffer_map (buffer, &map, GST_MAP_READ);
1974 
1975   /* Check for the FLV tag */
1976   if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1977     GST_DEBUG_OBJECT (demux, "FLV header detected");
1978   } else {
1979     if (G_UNLIKELY (demux->strict)) {
1980       GST_WARNING_OBJECT (demux, "invalid header tag detected");
1981       ret = GST_FLOW_EOS;
1982       goto beach;
1983     }
1984   }
1985 
1986   if (map.data[3] == '1') {
1987     GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1988   } else {
1989     if (G_UNLIKELY (demux->strict)) {
1990       GST_WARNING_OBJECT (demux, "invalid header version detected");
1991       ret = GST_FLOW_EOS;
1992       goto beach;
1993     }
1994 
1995   }
1996 
1997   /* Now look at audio/video flags */
1998   {
1999     guint8 flags = map.data[4];
2000 
2001     demux->has_video = demux->has_audio = FALSE;
2002 
2003     if (flags & 1) {
2004       GST_DEBUG_OBJECT (demux, "there is a video stream");
2005       demux->has_video = TRUE;
2006     }
2007     if (flags & 4) {
2008       GST_DEBUG_OBJECT (demux, "there is an audio stream");
2009       demux->has_audio = TRUE;
2010     }
2011   }
2012 
2013   /* do a one-time seekability check */
2014   gst_flv_demux_check_seekability (demux);
2015 
2016   /* We don't care about the rest */
2017   demux->need_header = FALSE;
2018 
2019 beach:
2020   gst_buffer_unmap (buffer, &map);
2021   return ret;
2022 }
2023 
2024 
2025 static void
gst_flv_demux_flush(GstFlvDemux * demux,gboolean discont)2026 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
2027 {
2028   GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
2029 
2030   gst_adapter_clear (demux->adapter);
2031 
2032   demux->audio_need_discont = TRUE;
2033   demux->video_need_discont = TRUE;
2034 
2035   demux->flushing = FALSE;
2036 
2037   /* Only in push mode and if we're not during a seek */
2038   if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
2039     /* After a flush we expect a tag_type */
2040     demux->state = FLV_STATE_TAG_TYPE;
2041     /* We reset the offset and will get one from first push */
2042     demux->offset = 0;
2043   }
2044 }
2045 
2046 static void
gst_flv_demux_cleanup(GstFlvDemux * demux)2047 gst_flv_demux_cleanup (GstFlvDemux * demux)
2048 {
2049   GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
2050 
2051   demux->state = FLV_STATE_HEADER;
2052 
2053   demux->have_group_id = FALSE;
2054   demux->group_id = G_MAXUINT;
2055 
2056   demux->flushing = FALSE;
2057   demux->need_header = TRUE;
2058   demux->audio_need_segment = TRUE;
2059   demux->video_need_segment = TRUE;
2060   demux->audio_need_discont = TRUE;
2061   demux->video_need_discont = TRUE;
2062 
2063   demux->has_audio = FALSE;
2064   demux->has_video = FALSE;
2065   demux->got_par = FALSE;
2066 
2067   demux->indexed = FALSE;
2068   demux->upstream_seekable = FALSE;
2069   demux->file_size = 0;
2070   demux->segment_seqnum = 0;
2071 
2072   demux->index_max_pos = 0;
2073   demux->index_max_time = 0;
2074 
2075   demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
2076   demux->last_audio_pts = demux->last_video_dts = 0;
2077   demux->audio_time_offset = demux->video_time_offset = 0;
2078 
2079   demux->no_more_pads = FALSE;
2080 
2081 #ifndef GST_DISABLE_DEBUG
2082   demux->no_audio_warned = FALSE;
2083   demux->no_video_warned = FALSE;
2084 #endif
2085 
2086   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
2087 
2088   demux->w = demux->h = 0;
2089   demux->framerate = 0.0;
2090   demux->par_x = demux->par_y = 1;
2091   demux->video_offset = 0;
2092   demux->audio_offset = 0;
2093   demux->offset = demux->cur_tag_offset = 0;
2094   demux->tag_size = demux->tag_data_size = 0;
2095   demux->duration = GST_CLOCK_TIME_NONE;
2096 
2097   if (demux->new_seg_event) {
2098     gst_event_unref (demux->new_seg_event);
2099     demux->new_seg_event = NULL;
2100   }
2101 
2102   gst_adapter_clear (demux->adapter);
2103 
2104   if (demux->audio_codec_data) {
2105     gst_buffer_unref (demux->audio_codec_data);
2106     demux->audio_codec_data = NULL;
2107   }
2108 
2109   if (demux->video_codec_data) {
2110     gst_buffer_unref (demux->video_codec_data);
2111     demux->video_codec_data = NULL;
2112   }
2113 
2114   if (demux->audio_pad) {
2115     gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
2116     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
2117     gst_object_unref (demux->audio_pad);
2118     demux->audio_pad = NULL;
2119   }
2120 
2121   if (demux->video_pad) {
2122     gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
2123     gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
2124     gst_object_unref (demux->video_pad);
2125     demux->video_pad = NULL;
2126   }
2127 
2128   if (demux->times) {
2129     g_array_free (demux->times, TRUE);
2130     demux->times = NULL;
2131   }
2132 
2133   if (demux->filepositions) {
2134     g_array_free (demux->filepositions, TRUE);
2135     demux->filepositions = NULL;
2136   }
2137 
2138   demux->video_bitrate = 0;
2139   demux->audio_bitrate = 0;
2140 
2141   gst_flv_demux_clear_tags (demux);
2142 }
2143 
2144 /*
2145  * Create and push a flushing seek event upstream
2146  */
2147 static gboolean
flv_demux_seek_to_offset(GstFlvDemux * demux,guint64 offset)2148 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
2149 {
2150   GstEvent *event;
2151   gboolean res = 0;
2152 
2153   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2154 
2155   event =
2156       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2157       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2158       GST_SEEK_TYPE_NONE, -1);
2159   if (demux->segment_seqnum != GST_SEQNUM_INVALID)
2160     gst_event_set_seqnum (event, demux->segment_seqnum);
2161 
2162   res = gst_pad_push_event (demux->sinkpad, event);
2163 
2164   if (res)
2165     demux->offset = offset;
2166   return res;
2167 }
2168 
2169 static GstFlowReturn
gst_flv_demux_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)2170 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
2171 {
2172   GstFlowReturn ret = GST_FLOW_OK;
2173   GstFlvDemux *demux = NULL;
2174 
2175   demux = GST_FLV_DEMUX (parent);
2176 
2177   GST_LOG_OBJECT (demux,
2178       "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
2179       G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
2180       GST_BUFFER_OFFSET (buffer));
2181 
2182   if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
2183     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
2184     demux->state = FLV_STATE_HEADER;
2185     demux->offset = 0;
2186   }
2187 
2188   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
2189     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2190     demux->offset = GST_BUFFER_OFFSET (buffer);
2191   }
2192 
2193   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
2194     GST_DEBUG_OBJECT (demux, "Discontinuity");
2195     gst_adapter_clear (demux->adapter);
2196   }
2197 
2198   gst_adapter_push (demux->adapter, buffer);
2199 
2200   if (demux->seeking) {
2201     demux->state = FLV_STATE_SEEK;
2202     GST_OBJECT_LOCK (demux);
2203     demux->seeking = FALSE;
2204     GST_OBJECT_UNLOCK (demux);
2205   }
2206 
2207 parse:
2208   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2209     GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
2210     goto beach;
2211   }
2212 
2213   if (G_UNLIKELY (demux->flushing)) {
2214     GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2215     ret = GST_FLOW_FLUSHING;
2216     goto beach;
2217   }
2218 
2219   switch (demux->state) {
2220     case FLV_STATE_HEADER:
2221     {
2222       if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
2223         GstBuffer *buffer;
2224 
2225         buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
2226 
2227         ret = gst_flv_demux_parse_header (demux, buffer);
2228 
2229         gst_buffer_unref (buffer);
2230         demux->offset += FLV_HEADER_SIZE;
2231 
2232         demux->state = FLV_STATE_TAG_TYPE;
2233         goto parse;
2234       } else {
2235         goto beach;
2236       }
2237     }
2238     case FLV_STATE_TAG_TYPE:
2239     {
2240       if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
2241         GstBuffer *buffer;
2242 
2243         /* Remember the tag offset in bytes */
2244         demux->cur_tag_offset = demux->offset;
2245 
2246         buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
2247 
2248         ret = gst_flv_demux_parse_tag_type (demux, buffer);
2249 
2250         gst_buffer_unref (buffer);
2251         demux->offset += FLV_TAG_TYPE_SIZE;
2252 
2253         /* last tag is not an index => no index/don't know where the index is
2254          * seek back to the beginning */
2255         if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2256           goto no_index;
2257 
2258         goto parse;
2259       } else {
2260         goto beach;
2261       }
2262     }
2263     case FLV_STATE_TAG_VIDEO:
2264     {
2265       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2266         GstBuffer *buffer;
2267 
2268         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2269 
2270         ret = gst_flv_demux_parse_tag_video (demux, buffer);
2271 
2272         gst_buffer_unref (buffer);
2273         demux->offset += demux->tag_size;
2274 
2275         demux->state = FLV_STATE_TAG_TYPE;
2276         goto parse;
2277       } else {
2278         goto beach;
2279       }
2280     }
2281     case FLV_STATE_TAG_AUDIO:
2282     {
2283       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2284         GstBuffer *buffer;
2285 
2286         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2287 
2288         ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2289 
2290         gst_buffer_unref (buffer);
2291         demux->offset += demux->tag_size;
2292 
2293         demux->state = FLV_STATE_TAG_TYPE;
2294         goto parse;
2295       } else {
2296         goto beach;
2297       }
2298     }
2299     case FLV_STATE_TAG_SCRIPT:
2300     {
2301       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2302         GstBuffer *buffer;
2303 
2304         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2305 
2306         ret = gst_flv_demux_parse_tag_script (demux, buffer);
2307 
2308         gst_buffer_unref (buffer);
2309         demux->offset += demux->tag_size;
2310 
2311         demux->state = FLV_STATE_TAG_TYPE;
2312 
2313         /* if there's a seek event we're here for the index so if we don't have it
2314          * we seek back to the beginning */
2315         if (demux->seek_event) {
2316           if (demux->indexed)
2317             demux->state = FLV_STATE_SEEK;
2318           else
2319             goto no_index;
2320         }
2321 
2322         goto parse;
2323       } else {
2324         goto beach;
2325       }
2326     }
2327     case FLV_STATE_SEEK:
2328     {
2329       GstEvent *event;
2330 
2331       ret = GST_FLOW_OK;
2332 
2333       if (!demux->indexed) {
2334         if (demux->offset == demux->file_size - sizeof (guint32)) {
2335           guint64 seek_offset;
2336           guint8 *data;
2337 
2338           data = gst_adapter_take (demux->adapter, 4);
2339           if (!data)
2340             goto no_index;
2341 
2342           seek_offset = demux->file_size - sizeof (guint32) -
2343               GST_READ_UINT32_BE (data);
2344           g_free (data);
2345 
2346           GST_INFO_OBJECT (demux,
2347               "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2348               seek_offset);
2349           demux->state = FLV_STATE_TAG_TYPE;
2350           flv_demux_seek_to_offset (demux, seek_offset);
2351           goto beach;
2352         } else
2353           goto no_index;
2354       }
2355 
2356       GST_OBJECT_LOCK (demux);
2357       event = demux->seek_event;
2358       demux->seek_event = NULL;
2359       GST_OBJECT_UNLOCK (demux);
2360 
2361       /* calculate and perform seek */
2362       if (!flv_demux_handle_seek_push (demux, event))
2363         goto seek_failed;
2364 
2365       gst_event_unref (event);
2366       demux->state = FLV_STATE_TAG_TYPE;
2367       goto beach;
2368     }
2369     case FLV_STATE_SKIP:
2370       /* Skip unknown tags (set in _parse_tag_type()) */
2371       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2372         gst_adapter_flush (demux->adapter, demux->tag_size);
2373         demux->offset += demux->tag_size;
2374         demux->state = FLV_STATE_TAG_TYPE;
2375         goto parse;
2376       } else {
2377         goto beach;
2378       }
2379     default:
2380       GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2381   }
2382 
2383 beach:
2384   return ret;
2385 
2386 /* ERRORS */
2387 no_index:
2388   {
2389     GST_OBJECT_LOCK (demux);
2390     demux->seeking = FALSE;
2391     gst_event_unref (demux->seek_event);
2392     demux->seek_event = NULL;
2393     GST_OBJECT_UNLOCK (demux);
2394     GST_WARNING_OBJECT (demux,
2395         "failed to find an index, seeking back to beginning");
2396     flv_demux_seek_to_offset (demux, 0);
2397     return GST_FLOW_OK;
2398   }
2399 seek_failed:
2400   {
2401     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2402     return GST_FLOW_ERROR;
2403   }
2404 
2405 }
2406 
2407 static GstFlowReturn
gst_flv_demux_pull_range(GstFlvDemux * demux,GstPad * pad,guint64 offset,guint size,GstBuffer ** buffer)2408 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2409     guint size, GstBuffer ** buffer)
2410 {
2411   GstFlowReturn ret;
2412 
2413   ret = gst_pad_pull_range (pad, offset, size, buffer);
2414   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2415     GST_WARNING_OBJECT (demux,
2416         "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2417         size, offset, gst_flow_get_name (ret));
2418     *buffer = NULL;
2419     return ret;
2420   }
2421 
2422   if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2423     GST_WARNING_OBJECT (demux,
2424         "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2425         G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2426     gst_buffer_unref (*buffer);
2427     ret = GST_FLOW_EOS;
2428     *buffer = NULL;
2429     return ret;
2430   }
2431 
2432   return ret;
2433 }
2434 
2435 static GstFlowReturn
gst_flv_demux_pull_tag(GstPad * pad,GstFlvDemux * demux)2436 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2437 {
2438   GstBuffer *buffer = NULL;
2439   GstFlowReturn ret = GST_FLOW_OK;
2440 
2441   /* Store tag offset */
2442   demux->cur_tag_offset = demux->offset;
2443 
2444   /* Get the first 4 bytes to identify tag type and size */
2445   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2446                   FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2447     goto beach;
2448 
2449   /* Identify tag type */
2450   ret = gst_flv_demux_parse_tag_type (demux, buffer);
2451 
2452   gst_buffer_unref (buffer);
2453 
2454   if (G_UNLIKELY (ret != GST_FLOW_OK))
2455     goto beach;
2456 
2457   /* Jump over tag type + size */
2458   demux->offset += FLV_TAG_TYPE_SIZE;
2459 
2460   /* Pull the whole tag */
2461   buffer = NULL;
2462   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2463                   demux->tag_size, &buffer)) != GST_FLOW_OK))
2464     goto beach;
2465 
2466   switch (demux->state) {
2467     case FLV_STATE_TAG_VIDEO:
2468       ret = gst_flv_demux_parse_tag_video (demux, buffer);
2469       break;
2470     case FLV_STATE_TAG_AUDIO:
2471       ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2472       break;
2473     case FLV_STATE_TAG_SCRIPT:
2474       ret = gst_flv_demux_parse_tag_script (demux, buffer);
2475       break;
2476     default:
2477       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2478   }
2479 
2480   gst_buffer_unref (buffer);
2481 
2482   /* Jump over that part we've just parsed */
2483   demux->offset += demux->tag_size;
2484 
2485   /* Make sure we reinitialize the tag size */
2486   demux->tag_size = 0;
2487 
2488   /* Ready for the next tag */
2489   demux->state = FLV_STATE_TAG_TYPE;
2490 
2491   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2492     GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2493         "neither video nor audio are linked");
2494   }
2495 
2496 beach:
2497   return ret;
2498 }
2499 
2500 static GstFlowReturn
gst_flv_demux_pull_header(GstPad * pad,GstFlvDemux * demux)2501 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2502 {
2503   GstBuffer *buffer = NULL;
2504   GstFlowReturn ret = GST_FLOW_OK;
2505 
2506   /* Get the first 9 bytes */
2507   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2508                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2509     goto beach;
2510 
2511   ret = gst_flv_demux_parse_header (demux, buffer);
2512 
2513   gst_buffer_unref (buffer);
2514 
2515   /* Jump over the header now */
2516   demux->offset += FLV_HEADER_SIZE;
2517   demux->state = FLV_STATE_TAG_TYPE;
2518 
2519 beach:
2520   return ret;
2521 }
2522 
2523 static void
gst_flv_demux_move_to_offset(GstFlvDemux * demux,gint64 offset,gboolean reset)2524 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2525     gboolean reset)
2526 {
2527   demux->offset = offset;
2528 
2529   /* Tell all the stream we moved to a different position (discont) */
2530   demux->audio_need_discont = TRUE;
2531   demux->video_need_discont = TRUE;
2532 
2533   /* next section setup */
2534   demux->from_offset = -1;
2535   demux->audio_done = demux->video_done = FALSE;
2536   demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2537 
2538   if (reset) {
2539     demux->from_offset = -1;
2540     demux->to_offset = G_MAXINT64;
2541   }
2542 
2543   /* If we seeked at the beginning of the file parse the header again */
2544   if (G_UNLIKELY (!demux->offset)) {
2545     demux->state = FLV_STATE_HEADER;
2546   } else {                      /* or parse a tag */
2547     demux->state = FLV_STATE_TAG_TYPE;
2548   }
2549 }
2550 
2551 static GstFlowReturn
gst_flv_demux_seek_to_prev_keyframe(GstFlvDemux * demux)2552 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2553 {
2554   GstFlowReturn ret = GST_FLOW_EOS;
2555   GstIndex *index;
2556   GstIndexEntry *entry = NULL;
2557 
2558   GST_DEBUG_OBJECT (demux,
2559       "terminated section started at offset %" G_GINT64_FORMAT,
2560       demux->from_offset);
2561 
2562   /* we are done if we got all audio and video */
2563   if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2564           demux->audio_first_ts < demux->segment.start) &&
2565       (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2566           demux->video_first_ts < demux->segment.start))
2567     goto done;
2568 
2569   if (demux->from_offset <= 0)
2570     goto done;
2571 
2572   GST_DEBUG_OBJECT (demux, "locating previous position");
2573 
2574   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2575 
2576   /* locate index entry before previous start position */
2577   if (index) {
2578     entry = gst_index_get_assoc_entry (index, demux->index_id,
2579         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2580         GST_FORMAT_BYTES, demux->from_offset - 1);
2581 
2582     if (entry) {
2583       gint64 bytes = 0, time = 0;
2584 
2585       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2586       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2587 
2588       GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2589           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2590           demux->offset - 1, GST_TIME_ARGS (time), bytes);
2591 
2592       /* setup for next section */
2593       demux->to_offset = demux->from_offset;
2594       gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2595       ret = GST_FLOW_OK;
2596     }
2597 
2598     gst_object_unref (index);
2599   }
2600 
2601 done:
2602   return ret;
2603 }
2604 
2605 static GstFlowReturn
gst_flv_demux_create_index(GstFlvDemux * demux,gint64 pos,GstClockTime ts)2606 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2607 {
2608   gint64 size;
2609   size_t tag_size;
2610   guint64 old_offset;
2611   GstBuffer *buffer;
2612   GstClockTime tag_time;
2613   GstFlowReturn ret = GST_FLOW_OK;
2614 
2615   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2616     return GST_FLOW_OK;
2617 
2618   GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2619       " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2620 
2621   old_offset = demux->offset;
2622   demux->offset = pos;
2623 
2624   buffer = NULL;
2625   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2626               12, &buffer)) == GST_FLOW_OK) {
2627     tag_time =
2628         gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2629 
2630     gst_buffer_unref (buffer);
2631     buffer = NULL;
2632 
2633     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2634       goto exit;
2635 
2636     demux->offset += tag_size;
2637   }
2638 
2639   if (ret == GST_FLOW_EOS) {
2640     /* file ran out, so mark we have complete index */
2641     demux->indexed = TRUE;
2642     ret = GST_FLOW_OK;
2643   }
2644 
2645 exit:
2646   demux->offset = old_offset;
2647 
2648   return ret;
2649 }
2650 
2651 static gint64
gst_flv_demux_get_metadata(GstFlvDemux * demux)2652 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2653 {
2654   gint64 ret = 0, offset;
2655   size_t tag_size, size;
2656   GstBuffer *buffer = NULL;
2657   GstMapInfo map;
2658 
2659   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2660     goto exit;
2661 
2662   ret = offset;
2663   GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2664   if (G_UNLIKELY (offset < 4))
2665     goto exit;
2666 
2667   offset -= 4;
2668   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2669           4, &buffer))
2670     goto exit;
2671 
2672   gst_buffer_map (buffer, &map, GST_MAP_READ);
2673   tag_size = GST_READ_UINT32_BE (map.data);
2674   gst_buffer_unmap (buffer, &map);
2675   GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2676   gst_buffer_unref (buffer);
2677   buffer = NULL;
2678 
2679   if (G_UNLIKELY (offset < tag_size))
2680     goto exit;
2681 
2682   offset -= tag_size;
2683   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2684           12, &buffer))
2685     goto exit;
2686 
2687   /* a consistency check */
2688   gst_buffer_map (buffer, &map, GST_MAP_READ);
2689   size = GST_READ_UINT24_BE (map.data + 1);
2690   if (size != tag_size - 11) {
2691     gst_buffer_unmap (buffer, &map);
2692     GST_DEBUG_OBJECT (demux,
2693         "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2694         ", corrupt or truncated file", size, tag_size - 11);
2695     goto exit;
2696   }
2697 
2698   /* try to update duration with timestamp in any case */
2699   gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2700 
2701   /* maybe get some more metadata */
2702   if (map.data[0] == 18) {
2703     gst_buffer_unmap (buffer, &map);
2704     gst_buffer_unref (buffer);
2705     buffer = NULL;
2706     GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2707     offset += 4;
2708     if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2709             tag_size, &buffer))
2710       gst_flv_demux_parse_tag_script (demux, buffer);
2711   } else {
2712     gst_buffer_unmap (buffer, &map);
2713   }
2714 
2715 exit:
2716   if (buffer)
2717     gst_buffer_unref (buffer);
2718 
2719   return ret;
2720 }
2721 
2722 static void
gst_flv_demux_loop(GstPad * pad)2723 gst_flv_demux_loop (GstPad * pad)
2724 {
2725   GstFlvDemux *demux = NULL;
2726   GstFlowReturn ret = GST_FLOW_OK;
2727 
2728   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2729 
2730   /* pull in data */
2731   switch (demux->state) {
2732     case FLV_STATE_TAG_TYPE:
2733       if (demux->from_offset == -1)
2734         demux->from_offset = demux->offset;
2735       ret = gst_flv_demux_pull_tag (pad, demux);
2736       /* if we have seen real data, we probably passed a possible metadata
2737        * header located at start.  So if we do not yet have an index,
2738        * try to pick up metadata (index, duration) at the end */
2739       if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2740               (demux->has_video || demux->has_audio)))
2741         demux->file_size = gst_flv_demux_get_metadata (demux);
2742       break;
2743     case FLV_STATE_DONE:
2744       ret = GST_FLOW_EOS;
2745       break;
2746     case FLV_STATE_SEEK:
2747       /* seek issued with insufficient index;
2748        * scan for index in task thread from current maximum offset to
2749        * desired time and then perform seek */
2750       /* TODO maybe some buffering message or so to indicate scan progress */
2751       ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2752           demux->seek_time);
2753       if (ret != GST_FLOW_OK)
2754         goto pause;
2755       /* position and state arranged by seek,
2756        * also unrefs event */
2757       gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2758       demux->seek_event = NULL;
2759       break;
2760     default:
2761       ret = gst_flv_demux_pull_header (pad, demux);
2762       /* index scans start after header */
2763       demux->index_max_pos = demux->offset;
2764       break;
2765   }
2766 
2767   if (demux->segment.rate < 0.0) {
2768     /* check end of section */
2769     if ((gint64) demux->offset >= demux->to_offset ||
2770         demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2771         (demux->audio_done && demux->video_done))
2772       ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2773   } else {
2774     /* check EOS condition */
2775     if ((demux->segment.stop != -1) &&
2776         (demux->segment.position >= demux->segment.stop)) {
2777       ret = GST_FLOW_EOS;
2778     }
2779   }
2780 
2781   /* pause if something went wrong or at end */
2782   if (G_UNLIKELY (ret != GST_FLOW_OK) && !(ret == GST_FLOW_NOT_LINKED
2783           && !demux->no_more_pads))
2784     goto pause;
2785 
2786   gst_object_unref (demux);
2787 
2788   return;
2789 
2790 pause:
2791   {
2792     const gchar *reason = gst_flow_get_name (ret);
2793     GstMessage *message;
2794     GstEvent *event;
2795 
2796     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2797     gst_pad_pause_task (pad);
2798 
2799     if (ret == GST_FLOW_EOS) {
2800       /* handle end-of-stream/segment */
2801       /* so align our position with the end of it, if there is one
2802        * this ensures a subsequent will arrive at correct base/acc time */
2803       if (demux->segment.rate > 0.0 &&
2804           GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2805         demux->segment.position = demux->segment.stop;
2806       else if (demux->segment.rate < 0.0)
2807         demux->segment.position = demux->segment.start;
2808 
2809       /* perform EOS logic */
2810       if (!demux->no_more_pads) {
2811         gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2812         demux->no_more_pads = TRUE;
2813       }
2814 
2815       if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2816         gint64 stop;
2817 
2818         /* for segment playback we need to post when (in stream time)
2819          * we stopped, this is either stop (when set) or the duration. */
2820         if ((stop = demux->segment.stop) == -1)
2821           stop = demux->segment.duration;
2822 
2823         if (demux->segment.rate >= 0) {
2824           GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2825           message = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2826               GST_FORMAT_TIME, stop);
2827           gst_message_set_seqnum (message, demux->segment_seqnum);
2828           gst_element_post_message (GST_ELEMENT_CAST (demux), message);
2829           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
2830           gst_event_set_seqnum (event, demux->segment_seqnum);
2831           gst_flv_demux_push_src_event (demux, event);
2832         } else {                /* Reverse playback */
2833           GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2834               "segment");
2835           message = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2836               GST_FORMAT_TIME, demux->segment.start);
2837           gst_message_set_seqnum (message, demux->segment_seqnum);
2838           gst_element_post_message (GST_ELEMENT_CAST (demux), message);
2839           event = gst_event_new_segment_done (GST_FORMAT_TIME,
2840               demux->segment.start);
2841           gst_event_set_seqnum (event, demux->segment_seqnum);
2842           gst_flv_demux_push_src_event (demux, event);
2843         }
2844       } else {
2845         /* normal playback, send EOS to all linked pads */
2846         if (!demux->no_more_pads) {
2847           gst_element_no_more_pads (GST_ELEMENT (demux));
2848           demux->no_more_pads = TRUE;
2849         }
2850 
2851         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2852         if (!demux->audio_pad && !demux->video_pad) {
2853           GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2854               ("Internal data stream error."), ("Got EOS before any data"));
2855         } else {
2856           event = gst_event_new_eos ();
2857           if (demux->segment_seqnum != GST_SEQNUM_INVALID)
2858             gst_event_set_seqnum (event, demux->segment_seqnum);
2859           if (!gst_flv_demux_push_src_event (demux, event))
2860             GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2861         }
2862       }
2863     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2864       GST_ELEMENT_FLOW_ERROR (demux, ret);
2865       event = gst_event_new_eos ();
2866       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
2867         gst_event_set_seqnum (event, demux->segment_seqnum);
2868       gst_flv_demux_push_src_event (demux, event);
2869     }
2870     gst_object_unref (demux);
2871     return;
2872   }
2873 }
2874 
2875 static guint64
gst_flv_demux_find_offset(GstFlvDemux * demux,GstSegment * segment,GstSeekFlags seek_flags)2876 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
2877     GstSeekFlags seek_flags)
2878 {
2879   gint64 bytes = 0;
2880   gint64 time = 0;
2881   GstIndex *index;
2882   GstIndexEntry *entry;
2883 
2884   g_return_val_if_fail (segment != NULL, 0);
2885 
2886   time = segment->position;
2887 
2888   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2889 
2890   if (index) {
2891     /* Let's check if we have an index entry for that seek time */
2892     entry = gst_index_get_assoc_entry (index, demux->index_id,
2893         seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
2894         GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
2895         GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
2896 
2897     if (entry) {
2898       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2899       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2900 
2901       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2902           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2903           GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2904 
2905       /* Key frame seeking */
2906       if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
2907         /* Adjust the segment so that the keyframe fits in */
2908         segment->start = segment->time = time;
2909         segment->position = time;
2910       }
2911     } else {
2912       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2913           GST_TIME_ARGS (segment->start));
2914     }
2915 
2916     gst_object_unref (index);
2917   }
2918 
2919   return bytes;
2920 }
2921 
2922 static gboolean
flv_demux_handle_seek_push(GstFlvDemux * demux,GstEvent * event)2923 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2924 {
2925   GstFormat format;
2926   GstSeekFlags flags;
2927   GstSeekType start_type, stop_type;
2928   gint64 start, stop;
2929   gdouble rate;
2930   gboolean update, flush, ret;
2931   GstSegment seeksegment;
2932 
2933   gst_event_parse_seek (event, &rate, &format, &flags,
2934       &start_type, &start, &stop_type, &stop);
2935 
2936   if (format != GST_FORMAT_TIME)
2937     goto wrong_format;
2938 
2939   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2940 
2941   /* Work on a copy until we are sure the seek succeeded. */
2942   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2943 
2944   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2945       &demux->segment);
2946 
2947   /* Apply the seek to our segment */
2948   gst_segment_do_seek (&seeksegment, rate, format, flags,
2949       start_type, start, stop_type, stop, &update);
2950 
2951   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2952       &seeksegment);
2953 
2954   if (flush || seeksegment.position != demux->segment.position) {
2955     /* Do the actual seeking */
2956     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
2957 
2958     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2959         G_GUINT64_FORMAT, offset);
2960     event = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2961         flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2962         offset, GST_SEEK_TYPE_NONE, 0);
2963     gst_event_set_seqnum (event, gst_event_get_seqnum (event));
2964     ret = gst_pad_push_event (demux->sinkpad, event);
2965     if (G_UNLIKELY (!ret)) {
2966       GST_WARNING_OBJECT (demux, "upstream seek failed");
2967     }
2968 
2969     gst_flow_combiner_reset (demux->flowcombiner);
2970     /* Tell all the stream we moved to a different position (discont) */
2971     demux->audio_need_discont = TRUE;
2972     demux->video_need_discont = TRUE;
2973   } else {
2974     ret = TRUE;
2975   }
2976 
2977   if (ret) {
2978     /* Ok seek succeeded, take the newly configured segment */
2979     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2980 
2981     /* Tell all the stream a new segment is needed */
2982     demux->audio_need_segment = TRUE;
2983     demux->video_need_segment = TRUE;
2984     /* Clean any potential newsegment event kept for the streams. The first
2985      * stream needing a new segment will create a new one. */
2986     if (G_UNLIKELY (demux->new_seg_event)) {
2987       gst_event_unref (demux->new_seg_event);
2988       demux->new_seg_event = NULL;
2989     }
2990     GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2991         GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2992         GST_TIME_ARGS (demux->segment.start),
2993         GST_TIME_ARGS (demux->segment.stop));
2994     demux->new_seg_event = gst_event_new_segment (&demux->segment);
2995     if (demux->segment_seqnum != GST_SEQNUM_INVALID)
2996       gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
2997     gst_event_unref (event);
2998   } else {
2999     ret = gst_pad_push_event (demux->sinkpad, event);
3000   }
3001 
3002   return ret;
3003 
3004 /* ERRORS */
3005 wrong_format:
3006   {
3007     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3008     gst_event_unref (event);
3009     return FALSE;
3010   }
3011 }
3012 
3013 static gboolean
gst_flv_demux_handle_seek_push(GstFlvDemux * demux,GstEvent * event)3014 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
3015 {
3016   GstFormat format;
3017 
3018   gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
3019 
3020   if (format != GST_FORMAT_TIME) {
3021     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3022     gst_event_unref (event);
3023     return FALSE;
3024   }
3025 
3026   /* First try upstream */
3027   if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
3028     GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
3029     gst_event_unref (event);
3030     return TRUE;
3031   }
3032 
3033   if (!demux->indexed) {
3034     guint64 seek_offset = 0;
3035     gboolean building_index;
3036 
3037     GST_OBJECT_LOCK (demux);
3038     /* handle the seek in the chain function */
3039     demux->seeking = TRUE;
3040     demux->state = FLV_STATE_SEEK;
3041 
3042     /* copy the event */
3043     gst_event_replace (&demux->seek_event, event);
3044 
3045     /* set the building_index flag so that only one thread can setup the
3046      * structures for index seeking. */
3047     building_index = demux->building_index;
3048     if (!building_index) {
3049       demux->building_index = TRUE;
3050       if (!demux->file_size
3051           && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
3052               &demux->file_size)) {
3053         GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
3054         GST_OBJECT_UNLOCK (demux);
3055         return FALSE;
3056       }
3057 
3058       /* we hope the last tag is a scriptdataobject containing an index
3059        * the size of the last tag is given in the last guint32 bits
3060        * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
3061       seek_offset = demux->file_size - sizeof (guint32);
3062       GST_DEBUG_OBJECT (demux,
3063           "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
3064     }
3065     GST_OBJECT_UNLOCK (demux);
3066 
3067     if (!building_index) {
3068       GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
3069           seek_offset);
3070       return flv_demux_seek_to_offset (demux, seek_offset);
3071     }
3072 
3073     /* FIXME: we have to always return true so that we don't block the seek
3074      * thread.
3075      * Note: maybe it is OK to return true if we're still building the index */
3076     return TRUE;
3077   }
3078 
3079   return flv_demux_handle_seek_push (demux, event);
3080 }
3081 
3082 static gboolean
gst_flv_demux_handle_seek_pull(GstFlvDemux * demux,GstEvent * event,gboolean seeking)3083 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
3084     gboolean seeking)
3085 {
3086   GstFormat format;
3087   GstSeekFlags flags;
3088   GstSeekType start_type, stop_type;
3089   gint64 start, stop;
3090   gdouble rate;
3091   gboolean update, flush, ret = FALSE;
3092   GstSegment seeksegment;
3093   GstEvent *flush_event;
3094   GstMessage *message;
3095   guint32 seqnum;
3096 
3097   gst_event_parse_seek (event, &rate, &format, &flags,
3098       &start_type, &start, &stop_type, &stop);
3099   seqnum = gst_event_get_seqnum (event);
3100 
3101   if (format != GST_FORMAT_TIME)
3102     goto wrong_format;
3103 
3104   /* mark seeking thread entering flushing/pausing */
3105   GST_OBJECT_LOCK (demux);
3106   if (seeking)
3107     demux->seeking = seeking;
3108   GST_OBJECT_UNLOCK (demux);
3109 
3110   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
3111 
3112   if (flush) {
3113     /* Flush start up and downstream to make sure data flow and loops are
3114        idle */
3115     flush_event = gst_event_new_flush_start ();
3116     gst_event_set_seqnum (flush_event, seqnum);
3117     gst_flv_demux_push_src_event (demux, flush_event);
3118 
3119     flush_event = gst_event_new_flush_start ();
3120     gst_event_set_seqnum (flush_event, seqnum);
3121     gst_pad_push_event (demux->sinkpad, flush_event);
3122   } else {
3123     /* Pause the pulling task */
3124     gst_pad_pause_task (demux->sinkpad);
3125   }
3126 
3127   /* Take the stream lock */
3128   GST_PAD_STREAM_LOCK (demux->sinkpad);
3129   demux->segment_seqnum = seqnum;
3130 
3131   if (flush) {
3132     /* Stop flushing upstream we need to pull */
3133     flush_event = gst_event_new_flush_stop (TRUE);
3134     gst_event_set_seqnum (flush_event, seqnum);
3135     gst_pad_push_event (demux->sinkpad, flush_event);
3136   }
3137 
3138   /* Work on a copy until we are sure the seek succeeded. */
3139   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
3140 
3141   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
3142       &demux->segment);
3143 
3144   /* Apply the seek to our segment */
3145   gst_segment_do_seek (&seeksegment, rate, format, flags,
3146       start_type, start, stop_type, stop, &update);
3147 
3148   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
3149       &seeksegment);
3150 
3151   if (flush || seeksegment.position != demux->segment.position) {
3152     /* Do the actual seeking */
3153     /* index is reliable if it is complete or we do not go to far ahead */
3154     if (seeking && !demux->indexed &&
3155         seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
3156       GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
3157           " index only up to %" GST_TIME_FORMAT,
3158           GST_TIME_ARGS (demux->index_max_time));
3159       /* stop flushing for now */
3160       if (flush) {
3161         flush_event = gst_event_new_flush_stop (TRUE);
3162         gst_event_set_seqnum (flush_event, seqnum);
3163         gst_flv_demux_push_src_event (demux, flush_event);
3164       }
3165       /* delegate scanning and index building to task thread to avoid
3166        * occupying main (UI) loop */
3167       if (demux->seek_event)
3168         gst_event_unref (demux->seek_event);
3169       demux->seek_event = gst_event_ref (event);
3170       demux->seek_time = seeksegment.position;
3171       demux->state = FLV_STATE_SEEK;
3172       /* do not know about success yet, but we did care and handled it */
3173       ret = TRUE;
3174       goto exit;
3175     }
3176 
3177     /* now index should be as reliable as it can be for current purpose */
3178     gst_flv_demux_move_to_offset (demux,
3179         gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
3180     ret = TRUE;
3181   } else {
3182     ret = TRUE;
3183   }
3184 
3185   if (flush) {
3186     /* Stop flushing, the sinks are at time 0 now */
3187     flush_event = gst_event_new_flush_stop (TRUE);
3188     gst_event_set_seqnum (flush_event, seqnum);
3189     gst_flv_demux_push_src_event (demux, flush_event);
3190   }
3191 
3192   if (ret) {
3193     /* Ok seek succeeded, take the newly configured segment */
3194     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3195 
3196     /* Notify about the start of a new segment */
3197     if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
3198       message = gst_message_new_segment_start (GST_OBJECT (demux),
3199           demux->segment.format, demux->segment.position);
3200       gst_message_set_seqnum (message, seqnum);
3201       gst_element_post_message (GST_ELEMENT (demux), message);
3202     }
3203 
3204     gst_flow_combiner_reset (demux->flowcombiner);
3205     /* Tell all the stream a new segment is needed */
3206     demux->audio_need_segment = TRUE;
3207     demux->video_need_segment = TRUE;
3208     /* Clean any potential newsegment event kept for the streams. The first
3209      * stream needing a new segment will create a new one. */
3210     if (G_UNLIKELY (demux->new_seg_event)) {
3211       gst_event_unref (demux->new_seg_event);
3212       demux->new_seg_event = NULL;
3213     }
3214     GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
3215         GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
3216         GST_TIME_ARGS (demux->segment.start),
3217         GST_TIME_ARGS (demux->segment.stop));
3218     demux->new_seg_event = gst_event_new_segment (&demux->segment);
3219     gst_event_set_seqnum (demux->new_seg_event, seqnum);
3220   }
3221 
3222 exit:
3223   GST_OBJECT_LOCK (demux);
3224   seeking = demux->seeking && !seeking;
3225   demux->seeking = FALSE;
3226   GST_OBJECT_UNLOCK (demux);
3227 
3228   /* if we detect an external seek having started (and possibly already having
3229    * flushed), do not restart task to give it a chance.
3230    * Otherwise external one's flushing will take care to pause task */
3231   if (seeking) {
3232     gst_pad_pause_task (demux->sinkpad);
3233   } else {
3234     gst_pad_start_task (demux->sinkpad,
3235         (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
3236   }
3237 
3238   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3239 
3240   gst_event_unref (event);
3241   return ret;
3242 
3243   /* ERRORS */
3244 wrong_format:
3245   {
3246     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3247     gst_event_unref (event);
3248     return ret;
3249   }
3250 }
3251 
3252 /* If we can pull that's preferred */
3253 static gboolean
gst_flv_demux_sink_activate(GstPad * sinkpad,GstObject * parent)3254 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3255 {
3256   GstQuery *query;
3257   gboolean pull_mode;
3258 
3259   query = gst_query_new_scheduling ();
3260 
3261   if (!gst_pad_peer_query (sinkpad, query)) {
3262     gst_query_unref (query);
3263     goto activate_push;
3264   }
3265 
3266   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
3267       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
3268   gst_query_unref (query);
3269 
3270   if (!pull_mode)
3271     goto activate_push;
3272 
3273   GST_DEBUG_OBJECT (sinkpad, "activating pull");
3274   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
3275 
3276 activate_push:
3277   {
3278     GST_DEBUG_OBJECT (sinkpad, "activating push");
3279     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3280   }
3281 }
3282 
3283 static gboolean
gst_flv_demux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)3284 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3285     GstPadMode mode, gboolean active)
3286 {
3287   gboolean res;
3288   GstFlvDemux *demux;
3289 
3290   demux = GST_FLV_DEMUX (parent);
3291 
3292   switch (mode) {
3293     case GST_PAD_MODE_PUSH:
3294       demux->random_access = FALSE;
3295       res = TRUE;
3296       break;
3297     case GST_PAD_MODE_PULL:
3298       if (active) {
3299         demux->random_access = TRUE;
3300         demux->segment_seqnum = gst_util_seqnum_next ();
3301         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3302             sinkpad, NULL);
3303       } else {
3304         demux->random_access = FALSE;
3305         res = gst_pad_stop_task (sinkpad);
3306       }
3307       break;
3308     default:
3309       res = FALSE;
3310       break;
3311   }
3312   return res;
3313 }
3314 
3315 static gboolean
gst_flv_demux_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)3316 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3317 {
3318   GstFlvDemux *demux;
3319   gboolean ret = FALSE;
3320 
3321   demux = GST_FLV_DEMUX (parent);
3322 
3323   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3324 
3325   switch (GST_EVENT_TYPE (event)) {
3326     case GST_EVENT_FLUSH_START:
3327       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3328       demux->flushing = TRUE;
3329       ret = gst_flv_demux_push_src_event (demux, event);
3330       break;
3331     case GST_EVENT_FLUSH_STOP:
3332       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3333       gst_flv_demux_flush (demux, TRUE);
3334       ret = gst_flv_demux_push_src_event (demux, event);
3335       break;
3336     case GST_EVENT_EOS:
3337     {
3338       GstIndex *index;
3339 
3340       GST_DEBUG_OBJECT (demux, "received EOS");
3341 
3342       index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3343 
3344       if (index) {
3345         GST_DEBUG_OBJECT (demux, "committing index");
3346         gst_index_commit (index, demux->index_id);
3347         gst_object_unref (index);
3348       }
3349 
3350       if (!demux->audio_pad && !demux->video_pad) {
3351         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3352             ("Internal data stream error."), ("Got EOS before any data"));
3353         gst_event_unref (event);
3354       } else {
3355         if (!demux->no_more_pads) {
3356           gst_element_no_more_pads (GST_ELEMENT (demux));
3357           demux->no_more_pads = TRUE;
3358         }
3359 
3360         if (!gst_flv_demux_push_src_event (demux, event))
3361           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3362       }
3363       ret = TRUE;
3364       break;
3365     }
3366     case GST_EVENT_SEGMENT:
3367     {
3368       GstSegment in_segment;
3369 
3370       GST_DEBUG_OBJECT (demux, "received new segment");
3371 
3372       gst_event_copy_segment (event, &in_segment);
3373       demux->segment_seqnum = gst_event_get_seqnum (event);
3374 
3375       if (in_segment.format == GST_FORMAT_TIME) {
3376         /* time segment, this is perfect, copy over the values. */
3377         memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3378 
3379         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3380             &demux->segment);
3381 
3382         /* and forward */
3383         ret = gst_flv_demux_push_src_event (demux, event);
3384       } else {
3385         /* non-time format */
3386         demux->audio_need_segment = TRUE;
3387         demux->video_need_segment = TRUE;
3388         ret = TRUE;
3389         gst_event_unref (event);
3390         if (demux->new_seg_event) {
3391           gst_event_unref (demux->new_seg_event);
3392           demux->new_seg_event = NULL;
3393         }
3394       }
3395       gst_flow_combiner_reset (demux->flowcombiner);
3396       break;
3397     }
3398     default:
3399       ret = gst_pad_event_default (pad, parent, event);
3400       break;
3401   }
3402 
3403   return ret;
3404 }
3405 
3406 static gboolean
gst_flv_demux_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)3407 gst_flv_demux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
3408 {
3409   GstFlvDemux *demux;
3410   gboolean ret = FALSE;
3411 
3412   demux = GST_FLV_DEMUX (parent);
3413 
3414   switch (GST_QUERY_TYPE (query)) {
3415     case GST_QUERY_BITRATE:
3416     {
3417       guint total_bitrate = 0;
3418 
3419       if (demux->audio_pad) {
3420         if (!demux->audio_bitrate) {
3421           GST_DEBUG_OBJECT (demux,
3422               "Have audio pad but no audio bitrate, can't answer BITRATE query");
3423           break;
3424         }
3425         total_bitrate = demux->audio_bitrate;
3426       }
3427       if (demux->video_pad) {
3428         if (!demux->video_bitrate) {
3429           GST_DEBUG_OBJECT (demux,
3430               "Have video pad but no video bitrate, can't answer BITRATE query");
3431           break;
3432         }
3433         total_bitrate += demux->video_bitrate;
3434       }
3435 
3436       GST_DEBUG_OBJECT (demux,
3437           "bitrate query. total_bitrate:%" G_GUINT32_FORMAT, total_bitrate);
3438 
3439       if (total_bitrate) {
3440         /* Padding of 2kbit/s for container overhead */
3441         gst_query_set_bitrate (query, total_bitrate + 2048);
3442         ret = TRUE;
3443       }
3444       break;
3445     }
3446     default:
3447       ret = gst_pad_query_default (pad, parent, query);
3448       break;
3449   }
3450 
3451   return ret;
3452 }
3453 
3454 static gboolean
gst_flv_demux_src_event(GstPad * pad,GstObject * parent,GstEvent * event)3455 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3456 {
3457   GstFlvDemux *demux;
3458   gboolean ret = FALSE;
3459 
3460   demux = GST_FLV_DEMUX (parent);
3461 
3462   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3463 
3464   switch (GST_EVENT_TYPE (event)) {
3465     case GST_EVENT_SEEK:
3466       /* Try to push upstream first */
3467       gst_event_ref (event);
3468       ret = gst_pad_push_event (demux->sinkpad, event);
3469       if (ret) {
3470         gst_event_unref (event);
3471         break;
3472       }
3473       if (demux->random_access) {
3474         ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3475       } else {
3476         ret = gst_flv_demux_handle_seek_push (demux, event);
3477       }
3478       break;
3479     default:
3480       ret = gst_pad_push_event (demux->sinkpad, event);
3481       break;
3482   }
3483 
3484   return ret;
3485 }
3486 
3487 static gboolean
gst_flv_demux_query(GstPad * pad,GstObject * parent,GstQuery * query)3488 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3489 {
3490   gboolean res = TRUE;
3491   GstFlvDemux *demux;
3492 
3493   demux = GST_FLV_DEMUX (parent);
3494 
3495   switch (GST_QUERY_TYPE (query)) {
3496     case GST_QUERY_DURATION:
3497     {
3498       GstFormat format;
3499 
3500       gst_query_parse_duration (query, &format, NULL);
3501 
3502       /* duration is time only */
3503       if (format != GST_FORMAT_TIME) {
3504         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3505             "format");
3506         res = FALSE;
3507         goto beach;
3508       }
3509 
3510       /* Try to push upstream first */
3511       res = gst_pad_peer_query (demux->sinkpad, query);
3512       if (res)
3513         goto beach;
3514 
3515       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3516           GST_TIME_ARGS (demux->duration));
3517 
3518       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3519       res = TRUE;
3520       break;
3521     }
3522     case GST_QUERY_POSITION:
3523     {
3524       GstFormat format;
3525 
3526       gst_query_parse_position (query, &format, NULL);
3527 
3528       /* position is time only */
3529       if (format != GST_FORMAT_TIME) {
3530         GST_DEBUG_OBJECT (demux, "position query only supported for time "
3531             "format");
3532         res = FALSE;
3533         goto beach;
3534       }
3535 
3536       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3537           GST_TIME_ARGS (demux->segment.position));
3538 
3539       gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3540 
3541       break;
3542     }
3543 
3544     case GST_QUERY_SEEKING:{
3545       GstFormat fmt;
3546 
3547       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3548 
3549       /* First ask upstream */
3550       if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3551         gboolean seekable;
3552 
3553         gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3554         if (seekable) {
3555           res = TRUE;
3556           break;
3557         }
3558       }
3559       res = TRUE;
3560       /* FIXME, check index this way is not thread safe */
3561       if (fmt != GST_FORMAT_TIME || !demux->index) {
3562         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3563       } else if (demux->random_access) {
3564         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3565             demux->duration);
3566       } else {
3567         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3568         gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3569 
3570         if (seekable)
3571           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3572         gst_query_unref (peerquery);
3573 
3574         if (seekable)
3575           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3576               demux->duration);
3577         else
3578           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3579       }
3580       break;
3581     }
3582     case GST_QUERY_SEGMENT:
3583     {
3584       GstFormat format;
3585       gint64 start, stop;
3586 
3587       format = demux->segment.format;
3588 
3589       start =
3590           gst_segment_to_stream_time (&demux->segment, format,
3591           demux->segment.start);
3592       if ((stop = demux->segment.stop) == -1)
3593         stop = demux->segment.duration;
3594       else
3595         stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3596 
3597       gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3598       res = TRUE;
3599       break;
3600     }
3601     case GST_QUERY_LATENCY:
3602     default:
3603       res = gst_pad_query_default (pad, parent, query);
3604       break;
3605   }
3606 
3607 beach:
3608 
3609   return res;
3610 }
3611 
3612 static GstStateChangeReturn
gst_flv_demux_change_state(GstElement * element,GstStateChange transition)3613 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3614 {
3615   GstFlvDemux *demux;
3616   GstStateChangeReturn ret;
3617 
3618   demux = GST_FLV_DEMUX (element);
3619 
3620   switch (transition) {
3621     case GST_STATE_CHANGE_READY_TO_PAUSED:
3622       /* If this is our own index destroy it as the
3623        * old entries might be wrong for the new stream */
3624       if (demux->own_index) {
3625         gst_object_unref (demux->index);
3626         demux->index = NULL;
3627         demux->own_index = FALSE;
3628       }
3629 
3630       /* If no index was created, generate one */
3631       if (G_UNLIKELY (!demux->index)) {
3632         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3633 
3634         demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3635 
3636         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3637             &demux->index_id);
3638         demux->own_index = TRUE;
3639       }
3640       gst_flv_demux_cleanup (demux);
3641       break;
3642     default:
3643       break;
3644   }
3645 
3646   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3647   if (ret == GST_STATE_CHANGE_FAILURE)
3648     return ret;
3649 
3650   switch (transition) {
3651     case GST_STATE_CHANGE_PAUSED_TO_READY:
3652       gst_flv_demux_cleanup (demux);
3653       break;
3654     default:
3655       break;
3656   }
3657 
3658   return ret;
3659 }
3660 
3661 #if 0
3662 static void
3663 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3664 {
3665   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3666   GstIndex *old_index;
3667 
3668   GST_OBJECT_LOCK (demux);
3669 
3670   old_index = demux->index;
3671 
3672   if (index) {
3673     demux->index = gst_object_ref (index);
3674     demux->own_index = FALSE;
3675   } else
3676     demux->index = NULL;
3677 
3678   if (old_index)
3679     gst_object_unref (demux->index);
3680 
3681   gst_object_ref (index);
3682 
3683   GST_OBJECT_UNLOCK (demux);
3684 
3685   /* object lock might be taken again */
3686   if (index)
3687     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3688 
3689   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3690 
3691   gst_object_unref (index);
3692 }
3693 #endif
3694 
3695 static GstIndex *
gst_flv_demux_get_index(GstElement * element)3696 gst_flv_demux_get_index (GstElement * element)
3697 {
3698   GstIndex *result = NULL;
3699 
3700   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3701 
3702   GST_OBJECT_LOCK (demux);
3703   if (demux->index)
3704     result = gst_object_ref (demux->index);
3705   GST_OBJECT_UNLOCK (demux);
3706 
3707   return result;
3708 }
3709 
3710 static void
gst_flv_demux_dispose(GObject * object)3711 gst_flv_demux_dispose (GObject * object)
3712 {
3713   GstFlvDemux *demux = GST_FLV_DEMUX (object);
3714 
3715   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3716 
3717   if (demux->adapter) {
3718     gst_adapter_clear (demux->adapter);
3719     g_object_unref (demux->adapter);
3720     demux->adapter = NULL;
3721   }
3722 
3723   if (demux->taglist) {
3724     gst_tag_list_unref (demux->taglist);
3725     demux->taglist = NULL;
3726   }
3727 
3728   if (demux->audio_tags) {
3729     gst_tag_list_unref (demux->audio_tags);
3730     demux->audio_tags = NULL;
3731   }
3732 
3733   if (demux->video_tags) {
3734     gst_tag_list_unref (demux->video_tags);
3735     demux->video_tags = NULL;
3736   }
3737 
3738   if (demux->flowcombiner) {
3739     gst_flow_combiner_free (demux->flowcombiner);
3740     demux->flowcombiner = NULL;
3741   }
3742 
3743   if (demux->new_seg_event) {
3744     gst_event_unref (demux->new_seg_event);
3745     demux->new_seg_event = NULL;
3746   }
3747 
3748   if (demux->audio_codec_data) {
3749     gst_buffer_unref (demux->audio_codec_data);
3750     demux->audio_codec_data = NULL;
3751   }
3752 
3753   if (demux->video_codec_data) {
3754     gst_buffer_unref (demux->video_codec_data);
3755     demux->video_codec_data = NULL;
3756   }
3757 
3758   if (demux->audio_pad) {
3759     gst_object_unref (demux->audio_pad);
3760     demux->audio_pad = NULL;
3761   }
3762 
3763   if (demux->video_pad) {
3764     gst_object_unref (demux->video_pad);
3765     demux->video_pad = NULL;
3766   }
3767 
3768   if (demux->index) {
3769     gst_object_unref (demux->index);
3770     demux->index = NULL;
3771   }
3772 
3773   if (demux->times) {
3774     g_array_free (demux->times, TRUE);
3775     demux->times = NULL;
3776   }
3777 
3778   if (demux->filepositions) {
3779     g_array_free (demux->filepositions, TRUE);
3780     demux->filepositions = NULL;
3781   }
3782 
3783   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3784 }
3785 
3786 static void
gst_flv_demux_class_init(GstFlvDemuxClass * klass)3787 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3788 {
3789   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3790   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3791 
3792   gobject_class->dispose = gst_flv_demux_dispose;
3793 
3794   gstelement_class->change_state =
3795       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3796 
3797 #if 0
3798   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3799   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3800 #endif
3801 
3802   gst_element_class_add_static_pad_template (gstelement_class,
3803       &flv_sink_template);
3804   gst_element_class_add_static_pad_template (gstelement_class,
3805       &audio_src_template);
3806   gst_element_class_add_static_pad_template (gstelement_class,
3807       &video_src_template);
3808   gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3809       "Codec/Demuxer", "Demux FLV feeds into digital streams",
3810       "Julien Moutte <julien@moutte.net>");
3811 }
3812 
3813 static void
gst_flv_demux_init(GstFlvDemux * demux)3814 gst_flv_demux_init (GstFlvDemux * demux)
3815 {
3816   demux->sinkpad =
3817       gst_pad_new_from_static_template (&flv_sink_template, "sink");
3818   GST_PAD_SET_ACCEPT_TEMPLATE (demux->sinkpad);
3819   gst_pad_set_event_function (demux->sinkpad,
3820       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3821   gst_pad_set_chain_function (demux->sinkpad,
3822       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3823   gst_pad_set_activate_function (demux->sinkpad,
3824       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3825   gst_pad_set_activatemode_function (demux->sinkpad,
3826       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3827   gst_pad_set_query_function (demux->sinkpad,
3828       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_query));
3829 
3830   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3831 
3832   demux->adapter = gst_adapter_new ();
3833   demux->flowcombiner = gst_flow_combiner_new ();
3834 
3835   demux->own_index = FALSE;
3836 
3837   GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3838 
3839   gst_flv_demux_cleanup (demux);
3840 }
3841