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