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