1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>,
3 * <2006> Edward Hervey <bilboed@bilboed.com>
4 * <2006> Wim Taymans <wim@fluendo.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include <libavformat/avformat.h>
29 #include <libavutil/imgutils.h>
30 /* #include <ffmpeg/avi.h> */
31 #include <gst/gst.h>
32 #include <gst/base/gstflowcombiner.h>
33
34 #include "gstav.h"
35 #include "gstavcodecmap.h"
36 #include "gstavutils.h"
37 #include "gstavprotocol.h"
38 #ifdef OHOS_EXT_FUNC
39 /**
40 * ohos.ext.func.0019
41 */
42 #include "gst/tag/tag.h"
43 #endif
44
45 #define MAX_STREAMS 20
46
47 typedef struct _GstFFMpegDemux GstFFMpegDemux;
48 typedef struct _GstFFStream GstFFStream;
49
50 struct _GstFFStream
51 {
52 GstPad *pad;
53
54 AVStream *avstream;
55
56 gboolean unknown;
57 GstClockTime last_ts;
58 gboolean discont;
59 gboolean eos;
60
61 GstTagList *tags; /* stream tags */
62 };
63
64 struct _GstFFMpegDemux
65 {
66 GstElement element;
67
68 /* We need to keep track of our pads, so we do so here. */
69 GstPad *sinkpad;
70
71 gboolean have_group_id;
72 guint group_id;
73
74 AVFormatContext *context;
75 gboolean opened;
76
77 GstFFStream *streams[MAX_STREAMS];
78
79 GstFlowCombiner *flowcombiner;
80
81 gint videopads, audiopads;
82
83 GstClockTime start_time;
84 GstClockTime duration;
85
86 /* TRUE if working in pull-mode */
87 gboolean seekable;
88
89 /* TRUE if the avformat demuxer can reliably handle streaming mode */
90 gboolean can_push;
91
92 gboolean flushing;
93
94 /* segment stuff */
95 GstSegment segment;
96
97 /* cached seek in READY */
98 GstEvent *seek_event;
99
100 /* cached upstream events */
101 GList *cached_events;
102
103 /* push mode data */
104 GstFFMpegPipe ffpipe;
105 GstTask *task;
106 GRecMutex task_lock;
107 };
108
109 typedef struct _GstFFMpegDemuxClass GstFFMpegDemuxClass;
110
111 struct _GstFFMpegDemuxClass
112 {
113 GstElementClass parent_class;
114
115 AVInputFormat *in_plugin;
116 GstPadTemplate *sinktempl;
117 GstPadTemplate *videosrctempl;
118 GstPadTemplate *audiosrctempl;
119 };
120
121 /* A number of function prototypes are given so we can refer to them later. */
122 static void gst_ffmpegdemux_class_init (GstFFMpegDemuxClass * klass);
123 static void gst_ffmpegdemux_base_init (GstFFMpegDemuxClass * klass);
124 static void gst_ffmpegdemux_init (GstFFMpegDemux * demux);
125 static void gst_ffmpegdemux_finalize (GObject * object);
126
127 static gboolean gst_ffmpegdemux_sink_event (GstPad * sinkpad,
128 GstObject * parent, GstEvent * event);
129 static GstFlowReturn gst_ffmpegdemux_chain (GstPad * sinkpad,
130 GstObject * parent, GstBuffer * buf);
131
132 static void gst_ffmpegdemux_loop (GstFFMpegDemux * demux);
133 static gboolean gst_ffmpegdemux_sink_activate (GstPad * sinkpad,
134 GstObject * parent);
135 static gboolean gst_ffmpegdemux_sink_activate_mode (GstPad * sinkpad,
136 GstObject * parent, GstPadMode mode, gboolean active);
137 static GstTagList *gst_ffmpeg_metadata_to_tag_list (AVDictionary * metadata);
138
139 #if 0
140 static gboolean
141 gst_ffmpegdemux_src_convert (GstPad * pad,
142 GstFormat src_fmt,
143 gint64 src_value, GstFormat * dest_fmt, gint64 * dest_value);
144 #endif
145 static gboolean
146 gst_ffmpegdemux_send_event (GstElement * element, GstEvent * event);
147 static GstStateChangeReturn
148 gst_ffmpegdemux_change_state (GstElement * element, GstStateChange transition);
149
150 #define GST_FFDEMUX_PARAMS_QDATA g_quark_from_static_string("avdemux-params")
151
152 static GstElementClass *parent_class = NULL;
153
154 static const gchar *
gst_ffmpegdemux_averror(gint av_errno)155 gst_ffmpegdemux_averror (gint av_errno)
156 {
157 const gchar *message = NULL;
158
159 switch (av_errno) {
160 case AVERROR (EINVAL):
161 message = "Unknown error";
162 break;
163 case AVERROR (EIO):
164 message = "Input/output error";
165 break;
166 case AVERROR (EDOM):
167 message = "Number syntax expected in filename";
168 break;
169 case AVERROR (ENOMEM):
170 message = "Not enough memory";
171 break;
172 case AVERROR (EILSEQ):
173 message = "Unknown format";
174 break;
175 case AVERROR (ENOSYS):
176 message = "Operation not supported";
177 break;
178 default:
179 message = "Unhandled error code received";
180 break;
181 }
182
183 return message;
184 }
185
186 static void
gst_ffmpegdemux_base_init(GstFFMpegDemuxClass * klass)187 gst_ffmpegdemux_base_init (GstFFMpegDemuxClass * klass)
188 {
189 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
190 AVInputFormat *in_plugin;
191 GstCaps *sinkcaps;
192 GstPadTemplate *sinktempl, *audiosrctempl, *videosrctempl;
193 gchar *longname, *description, *name;
194
195 in_plugin = (AVInputFormat *)
196 g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), GST_FFDEMUX_PARAMS_QDATA);
197 g_assert (in_plugin != NULL);
198
199 name = g_strdup (in_plugin->name);
200 g_strdelimit (name, ".,|-<> ", '_');
201
202 /* construct the element details struct */
203 longname = g_strdup_printf ("libav %s demuxer", in_plugin->long_name);
204 description = g_strdup_printf ("libav %s demuxer", in_plugin->long_name);
205 gst_element_class_set_metadata (element_class, longname,
206 "Codec/Demuxer", description,
207 "Wim Taymans <wim@fluendo.com>, "
208 "Ronald Bultje <rbultje@ronald.bitfreak.net>, "
209 "Edward Hervey <bilboed@bilboed.com>");
210 g_free (longname);
211 g_free (description);
212
213 /* pad templates */
214 sinkcaps = gst_ffmpeg_formatid_to_caps (name);
215 sinktempl = gst_pad_template_new ("sink",
216 GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps);
217 g_free (name);
218 videosrctempl = gst_pad_template_new ("video_%u",
219 GST_PAD_SRC, GST_PAD_SOMETIMES, GST_CAPS_ANY);
220 audiosrctempl = gst_pad_template_new ("audio_%u",
221 GST_PAD_SRC, GST_PAD_SOMETIMES, GST_CAPS_ANY);
222
223 gst_element_class_add_pad_template (element_class, videosrctempl);
224 gst_element_class_add_pad_template (element_class, audiosrctempl);
225 gst_element_class_add_pad_template (element_class, sinktempl);
226
227 gst_caps_unref (sinkcaps);
228
229 klass->in_plugin = in_plugin;
230 klass->videosrctempl = videosrctempl;
231 klass->audiosrctempl = audiosrctempl;
232 klass->sinktempl = sinktempl;
233 }
234
235 static void
gst_ffmpegdemux_class_init(GstFFMpegDemuxClass * klass)236 gst_ffmpegdemux_class_init (GstFFMpegDemuxClass * klass)
237 {
238 GObjectClass *gobject_class;
239 GstElementClass *gstelement_class;
240
241 gobject_class = (GObjectClass *) klass;
242 gstelement_class = (GstElementClass *) klass;
243
244 parent_class = g_type_class_peek_parent (klass);
245
246 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ffmpegdemux_finalize);
247
248 gstelement_class->change_state = gst_ffmpegdemux_change_state;
249 gstelement_class->send_event = gst_ffmpegdemux_send_event;
250 }
251
252 static void
gst_ffmpegdemux_init(GstFFMpegDemux * demux)253 gst_ffmpegdemux_init (GstFFMpegDemux * demux)
254 {
255 GstFFMpegDemuxClass *oclass =
256 (GstFFMpegDemuxClass *) (G_OBJECT_GET_CLASS (demux));
257 gint n;
258
259 demux->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
260 gst_pad_set_activate_function (demux->sinkpad,
261 GST_DEBUG_FUNCPTR (gst_ffmpegdemux_sink_activate));
262 gst_pad_set_activatemode_function (demux->sinkpad,
263 GST_DEBUG_FUNCPTR (gst_ffmpegdemux_sink_activate_mode));
264 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
265
266 /* push based setup */
267 /* the following are not used in pull-based mode, so safe to set anyway */
268 gst_pad_set_event_function (demux->sinkpad,
269 GST_DEBUG_FUNCPTR (gst_ffmpegdemux_sink_event));
270 gst_pad_set_chain_function (demux->sinkpad,
271 GST_DEBUG_FUNCPTR (gst_ffmpegdemux_chain));
272 /* task for driving ffmpeg in loop function */
273 demux->task =
274 gst_task_new ((GstTaskFunction) gst_ffmpegdemux_loop, demux, NULL);
275 g_rec_mutex_init (&demux->task_lock);
276 gst_task_set_lock (demux->task, &demux->task_lock);
277
278 demux->have_group_id = FALSE;
279 demux->group_id = G_MAXUINT;
280
281 demux->opened = FALSE;
282 demux->context = NULL;
283
284 for (n = 0; n < MAX_STREAMS; n++) {
285 demux->streams[n] = NULL;
286 }
287 demux->videopads = 0;
288 demux->audiopads = 0;
289
290 demux->seek_event = NULL;
291 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
292
293 demux->flowcombiner = gst_flow_combiner_new ();
294
295 /* push based data */
296 g_mutex_init (&demux->ffpipe.tlock);
297 g_cond_init (&demux->ffpipe.cond);
298 demux->ffpipe.adapter = gst_adapter_new ();
299
300 /* blacklist unreliable push-based demuxers */
301 if (strcmp (oclass->in_plugin->name, "ape"))
302 demux->can_push = TRUE;
303 else
304 demux->can_push = FALSE;
305 }
306
307 static void
gst_ffmpegdemux_finalize(GObject * object)308 gst_ffmpegdemux_finalize (GObject * object)
309 {
310 GstFFMpegDemux *demux;
311
312 demux = (GstFFMpegDemux *) object;
313
314 gst_flow_combiner_free (demux->flowcombiner);
315
316 g_mutex_clear (&demux->ffpipe.tlock);
317 g_cond_clear (&demux->ffpipe.cond);
318 gst_object_unref (demux->ffpipe.adapter);
319
320 gst_object_unref (demux->task);
321 g_rec_mutex_clear (&demux->task_lock);
322
323 G_OBJECT_CLASS (parent_class)->finalize (object);
324 }
325
326 static void
gst_ffmpegdemux_close(GstFFMpegDemux * demux)327 gst_ffmpegdemux_close (GstFFMpegDemux * demux)
328 {
329 gint n;
330 GstEvent **event_p;
331
332 if (!demux->opened)
333 return;
334
335 /* remove pads from ourselves */
336 for (n = 0; n < MAX_STREAMS; n++) {
337 GstFFStream *stream;
338
339 stream = demux->streams[n];
340 if (stream) {
341 if (stream->pad) {
342 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
343 gst_element_remove_pad (GST_ELEMENT (demux), stream->pad);
344 }
345 if (stream->tags)
346 gst_tag_list_unref (stream->tags);
347 g_free (stream);
348 }
349 demux->streams[n] = NULL;
350 }
351 demux->videopads = 0;
352 demux->audiopads = 0;
353
354 /* close demuxer context from ffmpeg */
355 if (demux->seekable)
356 gst_ffmpegdata_close (demux->context->pb);
357 else
358 gst_ffmpeg_pipe_close (demux->context->pb);
359 demux->context->pb = NULL;
360 avformat_close_input (&demux->context);
361 if (demux->context)
362 avformat_free_context (demux->context);
363 demux->context = NULL;
364
365 GST_OBJECT_LOCK (demux);
366 demux->opened = FALSE;
367 event_p = &demux->seek_event;
368 gst_event_replace (event_p, NULL);
369 GST_OBJECT_UNLOCK (demux);
370
371 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
372 }
373
374 /* send an event to all the source pads .
375 * Takes ownership of the event.
376 *
377 * Returns FALSE if none of the source pads handled the event.
378 */
379 static gboolean
gst_ffmpegdemux_push_event(GstFFMpegDemux * demux,GstEvent * event)380 gst_ffmpegdemux_push_event (GstFFMpegDemux * demux, GstEvent * event)
381 {
382 gboolean res;
383 gint n;
384
385 res = TRUE;
386
387 for (n = 0; n < MAX_STREAMS; n++) {
388 GstFFStream *s = demux->streams[n];
389
390 if (s && s->pad) {
391 gst_event_ref (event);
392 res &= gst_pad_push_event (s->pad, event);
393 }
394 }
395 gst_event_unref (event);
396
397 return res;
398 }
399
400 /* set flags on all streams */
401 static void
gst_ffmpegdemux_set_flags(GstFFMpegDemux * demux,gboolean discont,gboolean eos)402 gst_ffmpegdemux_set_flags (GstFFMpegDemux * demux, gboolean discont,
403 gboolean eos)
404 {
405 GstFFStream *s;
406 gint n;
407
408 for (n = 0; n < MAX_STREAMS; n++) {
409 if ((s = demux->streams[n])) {
410 s->discont = discont;
411 s->eos = eos;
412 }
413 }
414 }
415
416 /* check if all streams are eos */
417 static gboolean
gst_ffmpegdemux_is_eos(GstFFMpegDemux * demux)418 gst_ffmpegdemux_is_eos (GstFFMpegDemux * demux)
419 {
420 GstFFStream *s;
421 gint n;
422
423 for (n = 0; n < MAX_STREAMS; n++) {
424 if ((s = demux->streams[n])) {
425 GST_DEBUG ("stream %d %p eos:%d", n, s, s->eos);
426 if (!s->eos)
427 return FALSE;
428 }
429 }
430 return TRUE;
431 }
432
433 /* Returns True if we at least outputted one buffer */
434 static gboolean
gst_ffmpegdemux_has_outputted(GstFFMpegDemux * demux)435 gst_ffmpegdemux_has_outputted (GstFFMpegDemux * demux)
436 {
437 GstFFStream *s;
438 gint n;
439
440 for (n = 0; n < MAX_STREAMS; n++) {
441 if ((s = demux->streams[n])) {
442 if (GST_CLOCK_TIME_IS_VALID (s->last_ts))
443 return TRUE;
444 }
445 }
446 return FALSE;
447 }
448
449 static gboolean
gst_ffmpegdemux_do_seek(GstFFMpegDemux * demux,GstSegment * segment)450 gst_ffmpegdemux_do_seek (GstFFMpegDemux * demux, GstSegment * segment)
451 {
452 gboolean ret;
453 gint seekret;
454 gint64 target;
455 gint64 fftarget;
456 AVStream *stream;
457 gint index;
458
459 /* find default index and fail if none is present */
460 index = av_find_default_stream_index (demux->context);
461 GST_LOG_OBJECT (demux, "default stream index %d", index);
462 if (index < 0)
463 return FALSE;
464
465 ret = TRUE;
466
467 /* get the stream for seeking */
468 stream = demux->context->streams[index];
469 /* initial seek position */
470 target = segment->position + demux->start_time;
471 /* convert target to ffmpeg time */
472 fftarget = gst_ffmpeg_time_gst_to_ff (target, stream->time_base);
473
474 GST_LOG_OBJECT (demux, "do seek to time %" GST_TIME_FORMAT,
475 GST_TIME_ARGS (target));
476
477 /* if we need to land on a keyframe, try to do so, we don't try to do a
478 * keyframe seek if we are not absolutely sure we have an index.*/
479 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
480 gint keyframeidx;
481
482 GST_LOG_OBJECT (demux, "looking for keyframe in ffmpeg for time %"
483 GST_TIME_FORMAT, GST_TIME_ARGS (target));
484
485 /* search in the index for the previous keyframe */
486 keyframeidx =
487 av_index_search_timestamp (stream, fftarget, AVSEEK_FLAG_BACKWARD);
488
489 GST_LOG_OBJECT (demux, "keyframeidx: %d", keyframeidx);
490
491 if (keyframeidx >= 0) {
492 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58,78,0)
493 fftarget = avformat_index_get_entry (stream, keyframeidx)->timestamp;
494 #else
495 fftarget = stream->index_entries[keyframeidx].timestamp;
496 #endif
497 target = gst_ffmpeg_time_ff_to_gst (fftarget, stream->time_base);
498
499 GST_LOG_OBJECT (demux,
500 "Found a keyframe at ffmpeg idx: %d timestamp :%" GST_TIME_FORMAT,
501 keyframeidx, GST_TIME_ARGS (target));
502 }
503 }
504
505 GST_DEBUG_OBJECT (demux,
506 "About to call av_seek_frame (context, %d, %" G_GINT64_FORMAT
507 ", 0) for time %" GST_TIME_FORMAT, index, fftarget,
508 GST_TIME_ARGS (target));
509
510 if ((seekret =
511 av_seek_frame (demux->context, index, fftarget,
512 AVSEEK_FLAG_BACKWARD)) < 0)
513 goto seek_failed;
514
515 GST_DEBUG_OBJECT (demux, "seek success, returned %d", seekret);
516
517 if (target > demux->start_time)
518 target -= demux->start_time;
519 else
520 target = 0;
521
522 segment->position = target;
523 segment->time = target;
524 segment->start = target;
525
526 return ret;
527
528 /* ERRORS */
529 seek_failed:
530 {
531 GST_WARNING_OBJECT (demux, "Call to av_seek_frame failed : %d", seekret);
532 return FALSE;
533 }
534 }
535
536 static gboolean
gst_ffmpegdemux_perform_seek(GstFFMpegDemux * demux,GstEvent * event)537 gst_ffmpegdemux_perform_seek (GstFFMpegDemux * demux, GstEvent * event)
538 {
539 gboolean res;
540 gdouble rate;
541 GstFormat format;
542 GstSeekFlags flags;
543 GstSeekType cur_type, stop_type;
544 gint64 cur, stop;
545 gboolean flush;
546 gboolean update;
547 GstSegment seeksegment;
548
549 if (!demux->seekable) {
550 GST_DEBUG_OBJECT (demux, "in push mode; ignoring seek");
551 return FALSE;
552 }
553
554 GST_DEBUG_OBJECT (demux, "starting seek");
555
556 if (event) {
557 gst_event_parse_seek (event, &rate, &format, &flags,
558 &cur_type, &cur, &stop_type, &stop);
559
560 /* we have to have a format as the segment format. Try to convert
561 * if not. */
562 if (demux->segment.format != format) {
563 GstFormat fmt;
564
565 fmt = demux->segment.format;
566 res = TRUE;
567 /* FIXME, use source pad */
568 if (cur_type != GST_SEEK_TYPE_NONE && cur != -1)
569 res = gst_pad_query_convert (demux->sinkpad, format, cur, fmt, &cur);
570 if (res && stop_type != GST_SEEK_TYPE_NONE && stop != -1)
571 res = gst_pad_query_convert (demux->sinkpad, format, stop, fmt, &stop);
572 if (!res)
573 goto no_format;
574
575 format = fmt;
576 }
577 } else {
578 flags = 0;
579 }
580
581 flush = flags & GST_SEEK_FLAG_FLUSH;
582
583 /* ohos.opt.compat.0003: the demux of gstplayer does not process mp3 seek scenario correctly.
584 * As a result, when flush first and the loop pause second, the demux will seek failed.
585 * Now, we pause before flush start, this problem will not again.
586 */
587 #ifdef OHOS_OPT_COMPAT
588 if (flush) {
589 /* send flush start to downstream */
590 gst_ffmpegdemux_push_event (demux, gst_event_new_flush_start ());
591 }
592
593 GST_INFO_OBJECT (demux, "will pause demux sinkpad task");
594 gst_pad_pause_task (demux->sinkpad);
595 GST_INFO_OBJECT (demux, "demux sinkpad task paused");
596
597 if (flush) {
598 /* mark flushing so that the streaming thread can react on it */
599 GST_OBJECT_LOCK (demux);
600 demux->flushing = TRUE;
601 GST_OBJECT_UNLOCK (demux);
602 }
603
604 /* send flush start to up stream */
605 if (flush) {
606 GST_INFO_OBJECT (demux, "send flush start to upstream.");
607 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
608 }
609
610 GST_INFO_OBJECT (demux, "GST_PAD_STREAM_LOCK");
611 #else
612 /* send flush start */
613 if (flush) {
614 /* mark flushing so that the streaming thread can react on it */
615 GST_OBJECT_LOCK (demux);
616 demux->flushing = TRUE;
617 GST_OBJECT_UNLOCK (demux);
618 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
619 gst_ffmpegdemux_push_event (demux, gst_event_new_flush_start ());
620 } else {
621 gst_pad_pause_task (demux->sinkpad);
622 }
623 #endif
624
625 /* grab streaming lock, this should eventually be possible, either
626 * because the task is paused or our streaming thread stopped
627 * because our peer is flushing. */
628 GST_PAD_STREAM_LOCK (demux->sinkpad);
629
630 /* make copy into temp structure, we can only update the main one
631 * when we actually could do the seek. */
632 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
633
634 /* now configure the seek segment */
635 if (event) {
636 gst_segment_do_seek (&seeksegment, rate, format, flags,
637 cur_type, cur, stop_type, stop, &update);
638 }
639
640 GST_DEBUG_OBJECT (demux, "segment configured from %" G_GINT64_FORMAT
641 " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
642 seeksegment.start, seeksegment.stop, seeksegment.position);
643
644 /* make the sinkpad available for data passing since we might need
645 * it when doing the seek */
646 if (flush) {
647 GST_OBJECT_LOCK (demux);
648 demux->flushing = FALSE;
649 GST_OBJECT_UNLOCK (demux);
650 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
651 }
652
653 /* do the seek, segment.position contains new position. */
654 res = gst_ffmpegdemux_do_seek (demux, &seeksegment);
655
656 /* and prepare to continue streaming */
657 if (flush) {
658 /* send flush stop, peer will accept data and events again. We
659 * are not yet providing data as we still have the STREAM_LOCK. */
660 gst_ffmpegdemux_push_event (demux, gst_event_new_flush_stop (TRUE));
661 }
662 /* if successfull seek, we update our real segment and push
663 * out the new segment. */
664 if (res) {
665 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
666
667 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
668 gst_element_post_message (GST_ELEMENT (demux),
669 gst_message_new_segment_start (GST_OBJECT (demux),
670 demux->segment.format, demux->segment.position));
671 }
672
673 /* now send the newsegment, FIXME, do this from the streaming thread */
674 GST_DEBUG_OBJECT (demux, "Sending newsegment %" GST_SEGMENT_FORMAT,
675 &demux->segment);
676
677 gst_ffmpegdemux_push_event (demux, gst_event_new_segment (&demux->segment));
678 }
679
680 /* Mark discont on all srcpads and remove eos */
681 gst_ffmpegdemux_set_flags (demux, TRUE, FALSE);
682 gst_flow_combiner_reset (demux->flowcombiner);
683
684 /* and restart the task in case it got paused explicitely or by
685 * the FLUSH_START event we pushed out. */
686 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_ffmpegdemux_loop,
687 demux->sinkpad, NULL);
688
689 /* and release the lock again so we can continue streaming */
690 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
691
692 return res;
693
694 /* ERROR */
695 no_format:
696 {
697 GST_DEBUG_OBJECT (demux, "undefined format given, seek aborted.");
698 return FALSE;
699 }
700 }
701
702 static gboolean
gst_ffmpegdemux_src_event(GstPad * pad,GstObject * parent,GstEvent * event)703 gst_ffmpegdemux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
704 {
705 GstFFMpegDemux *demux;
706 gboolean res = TRUE;
707
708 demux = (GstFFMpegDemux *) parent;
709
710 switch (GST_EVENT_TYPE (event)) {
711 case GST_EVENT_SEEK:
712 res = gst_ffmpegdemux_perform_seek (demux, event);
713 gst_event_unref (event);
714 break;
715 case GST_EVENT_LATENCY:
716 res = gst_pad_push_event (demux->sinkpad, event);
717 break;
718 case GST_EVENT_NAVIGATION:
719 case GST_EVENT_QOS:
720 default:
721 res = FALSE;
722 gst_event_unref (event);
723 break;
724 }
725
726 return res;
727 }
728
729 static gboolean
gst_ffmpegdemux_send_event(GstElement * element,GstEvent * event)730 gst_ffmpegdemux_send_event (GstElement * element, GstEvent * event)
731 {
732 GstFFMpegDemux *demux = (GstFFMpegDemux *) (element);
733 gboolean res;
734
735 switch (GST_EVENT_TYPE (event)) {
736 case GST_EVENT_SEEK:
737 GST_OBJECT_LOCK (demux);
738 if (!demux->opened) {
739 GstEvent **event_p;
740
741 GST_DEBUG_OBJECT (demux, "caching seek event");
742 event_p = &demux->seek_event;
743 gst_event_replace (event_p, event);
744 GST_OBJECT_UNLOCK (demux);
745
746 res = TRUE;
747 } else {
748 GST_OBJECT_UNLOCK (demux);
749 res = gst_ffmpegdemux_perform_seek (demux, event);
750 gst_event_unref (event);
751 }
752 break;
753 default:
754 res = FALSE;
755 break;
756 }
757
758 return res;
759 }
760
761 static gboolean
gst_ffmpegdemux_src_query(GstPad * pad,GstObject * parent,GstQuery * query)762 gst_ffmpegdemux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
763 {
764 GstFFMpegDemux *demux;
765 GstFFStream *stream;
766 AVStream *avstream;
767 gboolean res = FALSE;
768
769 if (!(stream = gst_pad_get_element_private (pad)))
770 return FALSE;
771
772 avstream = stream->avstream;
773
774 demux = (GstFFMpegDemux *) parent;
775
776 switch (GST_QUERY_TYPE (query)) {
777 case GST_QUERY_POSITION:
778 {
779 GstFormat format;
780 gint64 timeposition;
781
782 gst_query_parse_position (query, &format, NULL);
783
784 timeposition = stream->last_ts;
785 if (!(GST_CLOCK_TIME_IS_VALID (timeposition)))
786 break;
787
788 switch (format) {
789 case GST_FORMAT_TIME:
790 gst_query_set_position (query, GST_FORMAT_TIME, timeposition);
791 res = TRUE;
792 break;
793 case GST_FORMAT_DEFAULT:
794 gst_query_set_position (query, GST_FORMAT_DEFAULT,
795 gst_util_uint64_scale (timeposition, avstream->avg_frame_rate.num,
796 GST_SECOND * avstream->avg_frame_rate.den));
797 res = TRUE;
798 break;
799 case GST_FORMAT_BYTES:
800 if (demux->videopads + demux->audiopads == 1 &&
801 GST_PAD_PEER (demux->sinkpad) != NULL)
802 res = gst_pad_query_default (pad, parent, query);
803 break;
804 default:
805 break;
806 }
807 }
808 break;
809 case GST_QUERY_DURATION:
810 {
811 GstFormat format;
812 gint64 timeduration;
813
814 gst_query_parse_duration (query, &format, NULL);
815
816 timeduration =
817 gst_ffmpeg_time_ff_to_gst (avstream->duration, avstream->time_base);
818 if (!(GST_CLOCK_TIME_IS_VALID (timeduration))) {
819 /* use duration of complete file if the stream duration is not known */
820 timeduration = demux->duration;
821 if (!(GST_CLOCK_TIME_IS_VALID (timeduration)))
822 break;
823 }
824
825 switch (format) {
826 case GST_FORMAT_TIME:
827 gst_query_set_duration (query, GST_FORMAT_TIME, timeduration);
828 res = TRUE;
829 break;
830 case GST_FORMAT_DEFAULT:
831 gst_query_set_duration (query, GST_FORMAT_DEFAULT,
832 gst_util_uint64_scale (timeduration, avstream->avg_frame_rate.num,
833 GST_SECOND * avstream->avg_frame_rate.den));
834 res = TRUE;
835 break;
836 case GST_FORMAT_BYTES:
837 if (demux->videopads + demux->audiopads == 1 &&
838 GST_PAD_PEER (demux->sinkpad) != NULL)
839 res = gst_pad_query_default (pad, parent, query);
840 break;
841 default:
842 break;
843 }
844 }
845 break;
846 case GST_QUERY_SEEKING:{
847 GstFormat format;
848 gboolean seekable;
849 gint64 dur = -1;
850
851 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
852 seekable = demux->seekable;
853 if (!gst_pad_query_duration (pad, format, &dur)) {
854 /* unlikely that we don't know duration but can seek */
855 seekable = FALSE;
856 dur = -1;
857 }
858 gst_query_set_seeking (query, format, seekable, 0, dur);
859 res = TRUE;
860 break;
861 }
862 case GST_QUERY_SEGMENT:{
863 GstFormat format;
864 gint64 start, stop;
865
866 format = demux->segment.format;
867
868 start =
869 gst_segment_to_stream_time (&demux->segment, format,
870 demux->segment.start);
871 if ((stop = demux->segment.stop) == -1)
872 stop = demux->segment.duration;
873 else
874 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
875
876 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
877 res = TRUE;
878 break;
879 }
880 default:
881 /* FIXME : ADD GST_QUERY_CONVERT */
882 res = gst_pad_query_default (pad, parent, query);
883 break;
884 }
885
886 return res;
887 }
888
889 #if 0
890 /* FIXME, reenable me */
891 static gboolean
892 gst_ffmpegdemux_src_convert (GstPad * pad,
893 GstFormat src_fmt,
894 gint64 src_value, GstFormat * dest_fmt, gint64 * dest_value)
895 {
896 GstFFStream *stream;
897 gboolean res = TRUE;
898 AVStream *avstream;
899
900 if (!(stream = gst_pad_get_element_private (pad)))
901 return FALSE;
902
903 avstream = stream->avstream;
904 if (avstream->codec->codec_type != AVMEDIA_TYPE_VIDEO)
905 return FALSE;
906
907 switch (src_fmt) {
908 case GST_FORMAT_TIME:
909 switch (*dest_fmt) {
910 case GST_FORMAT_DEFAULT:
911 *dest_value = gst_util_uint64_scale (src_value,
912 avstream->avg_frame_rate.num,
913 GST_SECOND * avstream->avg_frame_rate.den);
914 break;
915 default:
916 res = FALSE;
917 break;
918 }
919 break;
920 case GST_FORMAT_DEFAULT:
921 switch (*dest_fmt) {
922 case GST_FORMAT_TIME:
923 *dest_value = gst_util_uint64_scale (src_value,
924 GST_SECOND * avstream->avg_frame_rate.num,
925 avstream->avg_frame_rate.den);
926 break;
927 default:
928 res = FALSE;
929 break;
930 }
931 break;
932 default:
933 res = FALSE;
934 break;
935 }
936
937 return res;
938 }
939 #endif
940
941 static gchar *
gst_ffmpegdemux_create_padname(const gchar * templ,gint n)942 gst_ffmpegdemux_create_padname (const gchar * templ, gint n)
943 {
944 GString *string;
945
946 /* FIXME, we just want to printf the number according to the template but
947 * then the format string is not a literal and we can't check arguments and
948 * this generates a compiler error */
949 string = g_string_new (templ);
950 g_string_truncate (string, string->len - 2);
951 g_string_append_printf (string, "%u", n);
952
953 return g_string_free (string, FALSE);
954 }
955
956 #ifdef OHOS_EXT_FUNC
957 /**
958 * ohos.ext.func.0019
959 * FFmpeg generate one stream for one image, rather than treated it as the metadata. Transfer it
960 * to gst tag for unified manner to resolve album art picture.
961 */
962 static GstTagList *
gst_ffmpegdemux_add_image_tag(GstFFMpegDemux * demux,GstTagList * taglist)963 gst_ffmpegdemux_add_image_tag (GstFFMpegDemux * demux, GstTagList * taglist)
964 {
965 if (taglist == NULL) {
966 taglist = gst_tag_list_new_empty();
967 if (taglist == NULL) {
968 GST_WARNING_OBJECT(demux, "create taglist failed");
969 return NULL;
970 }
971 }
972
973 GstFFStream * stream = NULL;
974 AVStream * avstream = NULL;
975
976 for (gint i = 0; i < MAX_STREAMS; i++) {
977 stream = demux->streams[i];
978 if (stream == NULL || stream->avstream == NULL) {
979 continue;
980 }
981 avstream = stream->avstream;
982
983 if (!(avstream->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
984 continue;
985 }
986
987 if (avstream->attached_pic.data == NULL || avstream->attached_pic.size <= 0) {
988 continue;
989 }
990
991 GST_INFO_OBJECT (demux, "stream %d has attached pic, size: %d",
992 avstream->index, avstream->attached_pic.size);
993
994 /**
995 * We ignore the differences between different picture types except for the Front Conver.
996 */
997 GstTagImageType imageType = GST_TAG_IMAGE_TYPE_NONE;
998 AVDictionaryEntry * av_tag = av_dict_get (avstream->metadata, "comment", NULL, AV_DICT_MATCH_CASE);
999 if (av_tag != NULL) {
1000 if (!strcmp (av_tag->value, "Cover (front)")) {
1001 GST_INFO_OBJECT (demux, "stream %d has Cover (front) image", avstream->index);
1002 imageType = GST_TAG_IMAGE_TYPE_FRONT_COVER;
1003 }
1004 }
1005
1006 GstSample * image = gst_tag_image_data_to_image_sample (
1007 avstream->attached_pic.data,
1008 avstream->attached_pic.size,
1009 imageType);
1010 if (image == NULL) {
1011 GST_WARNING_OBJECT (demux, "stream %d convert image data to image sample failed", avstream->index);
1012 return taglist;
1013 }
1014
1015 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_IMAGE, image, NULL);
1016 gst_sample_unref (image);
1017 }
1018
1019 return taglist;
1020 }
1021 #endif
1022
1023 static GstFFStream *
gst_ffmpegdemux_get_stream(GstFFMpegDemux * demux,AVStream * avstream)1024 gst_ffmpegdemux_get_stream (GstFFMpegDemux * demux, AVStream * avstream)
1025 {
1026 GstFFMpegDemuxClass *oclass;
1027 GstPadTemplate *templ = NULL;
1028 GstPad *pad;
1029 GstCaps *caps;
1030 gint num;
1031 gchar *padname;
1032 const gchar *codec;
1033 AVCodecContext *ctx = NULL;
1034 GstFFStream *stream;
1035 GstEvent *event;
1036 gchar *stream_id;
1037
1038 oclass = (GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux);
1039
1040 if (demux->streams[avstream->index] != NULL)
1041 goto exists;
1042
1043 ctx = avcodec_alloc_context3 (NULL);
1044 avcodec_parameters_to_context (ctx, avstream->codecpar);
1045
1046 /* create new stream */
1047 stream = g_new0 (GstFFStream, 1);
1048 demux->streams[avstream->index] = stream;
1049
1050 /* mark stream as unknown */
1051 stream->unknown = TRUE;
1052 stream->discont = TRUE;
1053 stream->avstream = avstream;
1054 stream->last_ts = GST_CLOCK_TIME_NONE;
1055 stream->tags = NULL;
1056
1057 switch (ctx->codec_type) {
1058 case AVMEDIA_TYPE_VIDEO:
1059 templ = oclass->videosrctempl;
1060 num = demux->videopads++;
1061 /* These are not part of the codec parameters we built the
1062 * context from */
1063 ctx->framerate.num = avstream->r_frame_rate.num;
1064 ctx->framerate.den = avstream->r_frame_rate.den;
1065 break;
1066 case AVMEDIA_TYPE_AUDIO:
1067 templ = oclass->audiosrctempl;
1068 num = demux->audiopads++;
1069 break;
1070 default:
1071 goto unknown_type;
1072 }
1073
1074 /* get caps that belongs to this stream */
1075 caps = gst_ffmpeg_codecid_to_caps (ctx->codec_id, ctx, TRUE);
1076 if (caps == NULL)
1077 goto unknown_caps;
1078
1079 /* stream is known now */
1080 stream->unknown = FALSE;
1081
1082 /* create new pad for this stream */
1083 padname =
1084 gst_ffmpegdemux_create_padname (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ),
1085 num);
1086 pad = gst_pad_new_from_template (templ, padname);
1087 g_free (padname);
1088
1089 gst_pad_use_fixed_caps (pad);
1090 gst_pad_set_active (pad, TRUE);
1091
1092 gst_pad_set_query_function (pad, gst_ffmpegdemux_src_query);
1093 gst_pad_set_event_function (pad, gst_ffmpegdemux_src_event);
1094
1095 /* store pad internally */
1096 stream->pad = pad;
1097 gst_pad_set_element_private (pad, stream);
1098
1099 /* transform some useful info to GstClockTime and remember */
1100 {
1101 GstClockTime tmp;
1102
1103 /* FIXME, actually use the start_time in some way */
1104 tmp = gst_ffmpeg_time_ff_to_gst (avstream->start_time, avstream->time_base);
1105 GST_DEBUG_OBJECT (demux, "stream %d: start time: %" GST_TIME_FORMAT,
1106 avstream->index, GST_TIME_ARGS (tmp));
1107
1108 tmp = gst_ffmpeg_time_ff_to_gst (avstream->duration, avstream->time_base);
1109 GST_DEBUG_OBJECT (demux, "stream %d: duration: %" GST_TIME_FORMAT,
1110 avstream->index, GST_TIME_ARGS (tmp));
1111 }
1112
1113 demux->streams[avstream->index] = stream;
1114
1115
1116 stream_id =
1117 gst_pad_create_stream_id_printf (pad, GST_ELEMENT_CAST (demux), "%03u",
1118 avstream->index);
1119
1120 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
1121 if (event) {
1122 if (gst_event_parse_group_id (event, &demux->group_id))
1123 demux->have_group_id = TRUE;
1124 else
1125 demux->have_group_id = FALSE;
1126 gst_event_unref (event);
1127 } else if (!demux->have_group_id) {
1128 demux->have_group_id = TRUE;
1129 demux->group_id = gst_util_group_id_next ();
1130 }
1131 event = gst_event_new_stream_start (stream_id);
1132 if (demux->have_group_id)
1133 gst_event_set_group_id (event, demux->group_id);
1134
1135 gst_pad_push_event (pad, event);
1136 g_free (stream_id);
1137
1138 GST_INFO_OBJECT (pad, "adding pad with caps %" GST_PTR_FORMAT, caps);
1139 gst_pad_set_caps (pad, caps);
1140 gst_caps_unref (caps);
1141
1142 /* activate and add */
1143 gst_element_add_pad (GST_ELEMENT (demux), pad);
1144 gst_flow_combiner_add_pad (demux->flowcombiner, pad);
1145
1146 /* metadata */
1147 if ((codec = gst_ffmpeg_get_codecid_longname (ctx->codec_id))) {
1148 stream->tags = gst_ffmpeg_metadata_to_tag_list (avstream->metadata);
1149
1150 if (stream->tags == NULL)
1151 stream->tags = gst_tag_list_new_empty ();
1152
1153 gst_tag_list_add (stream->tags, GST_TAG_MERGE_REPLACE,
1154 (ctx->codec_type == AVMEDIA_TYPE_VIDEO) ?
1155 GST_TAG_VIDEO_CODEC : GST_TAG_AUDIO_CODEC, codec, NULL);
1156 }
1157
1158 done:
1159 if (ctx)
1160 avcodec_free_context (&ctx);
1161 return stream;
1162
1163 /* ERRORS */
1164 exists:
1165 {
1166 GST_DEBUG_OBJECT (demux, "Pad existed (stream %d)", avstream->index);
1167 stream = demux->streams[avstream->index];
1168 goto done;
1169 }
1170 unknown_type:
1171 {
1172 GST_WARNING_OBJECT (demux, "Unknown pad type %d", ctx->codec_type);
1173 goto done;
1174 }
1175 unknown_caps:
1176 {
1177 GST_WARNING_OBJECT (demux, "Unknown caps for codec %d", ctx->codec_id);
1178 goto done;
1179 }
1180 }
1181
1182 static gchar *
safe_utf8_copy(gchar * input)1183 safe_utf8_copy (gchar * input)
1184 {
1185 gchar *output;
1186
1187 if (!(g_utf8_validate (input, -1, NULL))) {
1188 output = g_convert (input, strlen (input),
1189 "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
1190 } else {
1191 output = g_strdup (input);
1192 }
1193
1194 return output;
1195 }
1196
1197 /* This is a list of standard tag keys taken from the avformat.h
1198 * header, without handling any variants. */
1199 static const struct
1200 {
1201 const gchar *ffmpeg_tag_name;
1202 const gchar *gst_tag_name;
1203 } tagmapping[] = {
1204 {
1205 "album", GST_TAG_ALBUM}, {
1206 "album_artist", GST_TAG_ALBUM_ARTIST}, {
1207 "artist", GST_TAG_ARTIST}, {
1208 /**
1209 * ohos.ext.func.0010
1210 *
1211 * add the mapping from ffmpeg's author label to GST_TAG_AUTHOR
1212 * for retrieving the author metadata from the media file.
1213 */
1214 #ifdef OHOS_EXT_FUNC
1215 "author", GST_TAG_AUTHOR}, {
1216 #endif
1217 "comment", GST_TAG_COMMENT}, {
1218 "composer", GST_TAG_COMPOSER}, {
1219 "copyright", GST_TAG_COPYRIGHT}, {
1220 /* Need to convert ISO 8601 to GstDateTime: */
1221 "creation_time", GST_TAG_DATE_TIME}, {
1222 /* Need to convert ISO 8601 to GDateTime: */
1223 "date", GST_TAG_DATE_TIME}, {
1224 "disc", GST_TAG_ALBUM_VOLUME_NUMBER}, {
1225 "encoder", GST_TAG_ENCODER}, {
1226 "encoded_by", GST_TAG_ENCODED_BY}, {
1227 "genre", GST_TAG_GENRE}, {
1228 "language", GST_TAG_LANGUAGE_CODE}, {
1229 "performer", GST_TAG_PERFORMER}, {
1230 "publisher", GST_TAG_PUBLISHER}, {
1231 "title", GST_TAG_TITLE}, {
1232 "track", GST_TAG_TRACK_NUMBER}
1233 };
1234
1235 static const gchar *
match_tag_name(gchar * ffmpeg_tag_name)1236 match_tag_name (gchar * ffmpeg_tag_name)
1237 {
1238 gint i;
1239 /**
1240 * ohos.opt.compat.0007
1241 * The tag's name obtained from the media file maybe not lowercase, ensure the
1242 * tag's name is all lowercase before comparing it with the hard-coded tag name.
1243 */
1244 #ifdef OHOS_OPT_COMPAT
1245 gchar *real_ffmpeg_tag_name;
1246
1247 g_return_val_if_fail(ffmpeg_tag_name != NULL, NULL);
1248
1249 real_ffmpeg_tag_name = g_ascii_strdown(ffmpeg_tag_name, -1);
1250 for (i = 0; i < G_N_ELEMENTS (tagmapping); i++) {
1251 if (!g_strcmp0 (tagmapping[i].ffmpeg_tag_name, real_ffmpeg_tag_name)) {
1252 g_free(real_ffmpeg_tag_name);
1253 return tagmapping[i].gst_tag_name;
1254 }
1255 }
1256 g_free(real_ffmpeg_tag_name);
1257 #else
1258 for (i = 0; i < G_N_ELEMENTS (tagmapping); i++) {
1259 if (!g_strcmp0 (tagmapping[i].ffmpeg_tag_name, ffmpeg_tag_name))
1260 return tagmapping[i].gst_tag_name;
1261 }
1262 #endif
1263 return NULL;
1264 }
1265
1266 static GstTagList *
gst_ffmpeg_metadata_to_tag_list(AVDictionary * metadata)1267 gst_ffmpeg_metadata_to_tag_list (AVDictionary * metadata)
1268 {
1269 AVDictionaryEntry *tag = NULL;
1270 GstTagList *list;
1271 list = gst_tag_list_new_empty ();
1272
1273 while ((tag = av_dict_get (metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
1274 const gchar *gsttag = match_tag_name (tag->key);
1275 GType t;
1276 GST_LOG ("mapping tag %s=%s\n", tag->key, tag->value);
1277 if (gsttag == NULL) {
1278 GST_LOG ("Ignoring unknown metadata tag %s", tag->key);
1279 continue;
1280 }
1281 /* Special case, track and disc numbers may be x/n in libav, split
1282 * them */
1283 if (g_str_equal (gsttag, GST_TAG_TRACK_NUMBER)) {
1284 guint track, trackcount;
1285 if (sscanf (tag->value, "%u/%u", &track, &trackcount) == 2) {
1286 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
1287 gsttag, track, GST_TAG_TRACK_COUNT, trackcount, NULL);
1288 continue;
1289 }
1290 /* Fall through and handle as a single uint below */
1291 } else if (g_str_equal (gsttag, GST_TAG_ALBUM_VOLUME_NUMBER)) {
1292 guint disc, disc_count;
1293 if (sscanf (tag->value, "%u/%u", &disc, &disc_count) == 2) {
1294 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
1295 gsttag, disc, GST_TAG_ALBUM_VOLUME_COUNT, disc_count, NULL);
1296 continue;
1297 }
1298 /* Fall through and handle as a single uint below */
1299 }
1300
1301 t = gst_tag_get_type (gsttag);
1302 if (t == G_TYPE_STRING) {
1303 gchar *s = safe_utf8_copy (tag->value);
1304 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, gsttag, s, NULL);
1305 g_free (s);
1306 } else if (t == G_TYPE_UINT || t == G_TYPE_INT) {
1307 gchar *end;
1308 gint v = strtol (tag->value, &end, 10);
1309 if (end == tag->value)
1310 continue; /* Failed to parse */
1311 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, gsttag, v, NULL);
1312 } else if (t == G_TYPE_DATE) {
1313 guint year, month, day;
1314 GDate *date = NULL;
1315 if (sscanf (tag->value, "%04u-%02u-%02u", &year, &month, &day) == 3) {
1316 date = g_date_new_dmy (day, month, year);
1317 } else {
1318 /* Try interpreting just as a year */
1319 gchar *end;
1320
1321 year = strtol (tag->value, &end, 10);
1322 if (end != tag->value)
1323 date = g_date_new_dmy (1, 1, year);
1324 }
1325 if (date) {
1326 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, gsttag, date, NULL);
1327 g_date_free (date);
1328 }
1329 } else if (t == GST_TYPE_DATE_TIME) {
1330 gchar *s = safe_utf8_copy (tag->value);
1331 GstDateTime *d = gst_date_time_new_from_iso8601_string (s);
1332
1333 g_free (s);
1334 if (d) {
1335 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, gsttag, d, NULL);
1336 gst_date_time_unref (d);
1337 }
1338 } else {
1339 GST_FIXME ("Unhandled tag %s", gsttag);
1340 }
1341 }
1342
1343 if (gst_tag_list_is_empty (list)) {
1344 gst_tag_list_unref (list);
1345 return NULL;
1346 }
1347
1348 return list;
1349 }
1350
1351 static gboolean
gst_ffmpegdemux_open(GstFFMpegDemux * demux)1352 gst_ffmpegdemux_open (GstFFMpegDemux * demux)
1353 {
1354 AVIOContext *iocontext = NULL;
1355 GstFFMpegDemuxClass *oclass =
1356 (GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux);
1357 gint res, n_streams, i;
1358 GstTagList *tags;
1359 GstEvent *event;
1360 GList *cached_events;
1361 #ifndef OHOS_EXT_FUNC
1362 /**
1363 * ohos.ext.func.0030
1364 * we use the gstreamer's src element to process uri donwload, no need to use the ffmpeg's protocal
1365 * process capability.
1366 */
1367 GstQuery *query;
1368 gchar *uri = NULL;
1369 #endif
1370
1371 /* to be sure... */
1372 gst_ffmpegdemux_close (demux);
1373
1374 /* open via our input protocol hack */
1375 if (demux->seekable)
1376 res = gst_ffmpegdata_open (demux->sinkpad, AVIO_FLAG_READ, &iocontext);
1377 else
1378 res = gst_ffmpeg_pipe_open (&demux->ffpipe, AVIO_FLAG_READ, &iocontext);
1379
1380 if (res < 0)
1381 goto beach;
1382
1383 #ifndef OHOS_EXT_FUNC
1384 /**
1385 * ohos.ext.func.0030
1386 */
1387 query = gst_query_new_uri ();
1388 if (gst_pad_peer_query (demux->sinkpad, query)) {
1389 gchar *query_uri, *redirect_uri;
1390 gboolean permanent;
1391
1392 gst_query_parse_uri (query, &query_uri);
1393 gst_query_parse_uri_redirection (query, &redirect_uri);
1394 gst_query_parse_uri_redirection_permanent (query, &permanent);
1395
1396 if (permanent && redirect_uri) {
1397 uri = redirect_uri;
1398 g_free (query_uri);
1399 } else {
1400 uri = query_uri;
1401 g_free (redirect_uri);
1402 }
1403 }
1404 gst_query_unref (query);
1405
1406 GST_DEBUG_OBJECT (demux, "Opening context with URI %s", GST_STR_NULL (uri));
1407 #endif
1408
1409 demux->context = avformat_alloc_context ();
1410 demux->context->pb = iocontext;
1411
1412 #ifdef OHOS_EXT_FUNC
1413 /* ohos.ext.func.0030 */
1414 res = avformat_open_input (&demux->context, NULL, oclass->in_plugin, NULL);
1415 #else
1416 res = avformat_open_input (&demux->context, uri, oclass->in_plugin, NULL);
1417
1418 g_free (uri);
1419 #endif
1420
1421 GST_DEBUG_OBJECT (demux, "av_open_input returned %d", res);
1422 if (res < 0)
1423 goto beach;
1424
1425 res = gst_ffmpeg_av_find_stream_info (demux->context);
1426 GST_DEBUG_OBJECT (demux, "av_find_stream_info returned %d", res);
1427 if (res < 0)
1428 goto beach;
1429
1430 n_streams = demux->context->nb_streams;
1431 GST_DEBUG_OBJECT (demux, "we have %d streams", n_streams);
1432
1433 /* open_input_file() automatically reads the header. We can now map each
1434 * created AVStream to a GstPad to make GStreamer handle it. */
1435 for (i = 0; i < n_streams; i++) {
1436 gst_ffmpegdemux_get_stream (demux, demux->context->streams[i]);
1437 }
1438
1439 gst_element_no_more_pads (GST_ELEMENT (demux));
1440
1441 /* transform some useful info to GstClockTime and remember */
1442 demux->start_time = gst_util_uint64_scale_int (demux->context->start_time,
1443 GST_SECOND, AV_TIME_BASE);
1444 GST_DEBUG_OBJECT (demux, "start time: %" GST_TIME_FORMAT,
1445 GST_TIME_ARGS (demux->start_time));
1446 if (demux->context->duration > 0)
1447 demux->duration = gst_util_uint64_scale_int (demux->context->duration,
1448 GST_SECOND, AV_TIME_BASE);
1449 else
1450 demux->duration = GST_CLOCK_TIME_NONE;
1451
1452 GST_DEBUG_OBJECT (demux, "duration: %" GST_TIME_FORMAT,
1453 GST_TIME_ARGS (demux->duration));
1454
1455 /* store duration in the segment as well */
1456 demux->segment.duration = demux->duration;
1457
1458 GST_OBJECT_LOCK (demux);
1459 demux->opened = TRUE;
1460 event = demux->seek_event;
1461 demux->seek_event = NULL;
1462 cached_events = demux->cached_events;
1463 demux->cached_events = NULL;
1464 GST_OBJECT_UNLOCK (demux);
1465
1466 if (event) {
1467 gst_ffmpegdemux_perform_seek (demux, event);
1468 gst_event_unref (event);
1469 } else {
1470 GST_DEBUG_OBJECT (demux, "Sending segment %" GST_SEGMENT_FORMAT,
1471 &demux->segment);
1472 gst_ffmpegdemux_push_event (demux, gst_event_new_segment (&demux->segment));
1473 }
1474
1475 while (cached_events) {
1476 event = cached_events->data;
1477 GST_INFO_OBJECT (demux, "pushing cached event: %" GST_PTR_FORMAT, event);
1478 gst_ffmpegdemux_push_event (demux, event);
1479 cached_events = g_list_delete_link (cached_events, cached_events);
1480 }
1481
1482 /* grab the global tags */
1483 tags = gst_ffmpeg_metadata_to_tag_list (demux->context->metadata);
1484 if (tags) {
1485 GST_INFO_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, tags);
1486 }
1487
1488 #ifdef OHOS_EXT_FUNC
1489 /**
1490 * ohos.ext.func.0019
1491 *
1492 * Only add the image to global tags. The ffmpeg will create a new stream for each
1493 * image, but it is a fake stream, the decodebin maybe not able to autoplug a downstream
1494 * pipeline for it. Thus, we can not add the image to the stream tags, the tags from
1495 * the fake stream can not be sended to downstream.
1496 */
1497 tags = gst_ffmpegdemux_add_image_tag(demux, tags);
1498 gst_tag_list_set_scope(tags, GST_TAG_SCOPE_GLOBAL);
1499 #endif
1500
1501 /* now handle the stream tags */
1502 for (i = 0; i < n_streams; i++) {
1503 GstFFStream *stream;
1504
1505 stream = gst_ffmpegdemux_get_stream (demux, demux->context->streams[i]);
1506 if (stream->pad != NULL) {
1507
1508 /* Global tags */
1509 if (tags)
1510 gst_pad_push_event (stream->pad,
1511 gst_event_new_tag (gst_tag_list_ref (tags)));
1512
1513 /* Per-stream tags */
1514 if (stream->tags != NULL) {
1515 GST_INFO_OBJECT (stream->pad, "stream tags: %" GST_PTR_FORMAT,
1516 stream->tags);
1517 gst_pad_push_event (stream->pad,
1518 gst_event_new_tag (gst_tag_list_ref (stream->tags)));
1519 }
1520 }
1521 }
1522 if (tags)
1523 gst_tag_list_unref (tags);
1524 return TRUE;
1525
1526 /* ERRORS */
1527 beach:
1528 {
1529 GST_ELEMENT_ERROR (demux, LIBRARY, FAILED, (NULL),
1530 ("%s", gst_ffmpegdemux_averror (res)));
1531 return FALSE;
1532 }
1533 }
1534
1535 #define GST_FFMPEG_TYPE_FIND_SIZE 4096
1536 #define GST_FFMPEG_TYPE_FIND_MIN_SIZE 256
1537 #ifdef OHOS_OPT_COMPAT
1538 /* ohos.opt.compat.0005
1539 * Insufficient data read by the avdemux during the typefind process in the MP3 format.
1540 * As a result, the device is mistakenly identified as video/h264.
1541 * In the typefind of ffmpeg, if the score is 25 and the format is mp3,
1542 * obtain more data and re-judge. In the typefindhelper,
1543 * data may have been obtained but subsequent flows may not be obtained.
1544 * As a result, EOS is returned. Check the EOS. If prob exists, change the value to ok.
1545 * Otherwise, the value is error.
1546 */
1547 #define GST_FFMPEG_TYPE_FIND_MAX_SIZE (2UL<<20)
1548 #define GST_FFMPEG_MP3_INCOMPLETE_SCORE 25
1549 #endif
1550
1551 static void
gst_ffmpegdemux_type_find(GstTypeFind * tf,gpointer priv)1552 gst_ffmpegdemux_type_find (GstTypeFind * tf, gpointer priv)
1553 {
1554 const guint8 *data;
1555 AVInputFormat *in_plugin = (AVInputFormat *) priv;
1556 gint res = 0;
1557 guint64 length;
1558 GstCaps *sinkcaps;
1559
1560 /* We want GST_FFMPEG_TYPE_FIND_SIZE bytes, but if the file is shorter than
1561 * that we'll give it a try... */
1562 length = gst_type_find_get_length (tf);
1563 #ifdef OHOS_OPT_COMPAT
1564 // ohos.opt.compat.0005
1565 guint64 realLen = MIN (length, GST_FFMPEG_TYPE_FIND_MAX_SIZE);
1566 #endif
1567 if (length == 0 || length > GST_FFMPEG_TYPE_FIND_SIZE)
1568 length = GST_FFMPEG_TYPE_FIND_SIZE;
1569
1570 /* The ffmpeg typefinders assume there's a certain minimum amount of data
1571 * and will happily do invalid memory access if there isn't, so let's just
1572 * skip the ffmpeg typefinders if the data available is too short
1573 * (in which case it's unlikely to be a media file anyway) */
1574 if (length < GST_FFMPEG_TYPE_FIND_MIN_SIZE) {
1575 GST_LOG ("not typefinding %" G_GUINT64_FORMAT " bytes, too short", length);
1576 return;
1577 }
1578
1579 GST_LOG ("typefinding %" G_GUINT64_FORMAT " bytes", length);
1580 #ifdef OHOS_OPT_COMPAT
1581 /*
1582 * ohos.opt.compat.0016
1583 * obtaining parsed data fails due to insufficient data
1584 */
1585 data = gst_type_find_peek (tf, 0, length);
1586 if (data == NULL) {
1587 tf->need_typefind_again = TRUE;
1588 } else if (in_plugin->read_probe && data != NULL) {
1589 #else
1590 if (in_plugin->read_probe &&
1591 (data = gst_type_find_peek (tf, 0, length)) != NULL) {
1592 #endif
1593 AVProbeData probe_data;
1594
1595 probe_data.filename = "";
1596 probe_data.buf = (guint8 *) data;
1597 probe_data.buf_size = length;
1598
1599 res = in_plugin->read_probe (&probe_data);
1600 if (res > 0) {
1601 res = MAX (1, res * GST_TYPE_FIND_MAXIMUM / AVPROBE_SCORE_MAX);
1602 #ifdef OHOS_OPT_COMPAT
1603 // ohos.opt.compat.0005
1604 if (g_str_has_prefix (in_plugin->name, "mp3") && res == GST_FFMPEG_MP3_INCOMPLETE_SCORE &&
1605 (data = gst_type_find_peek (tf, 0, realLen)) != NULL) {
1606 probe_data.filename = "";
1607 probe_data.buf = (guint8 *) data;
1608 probe_data.buf_size = realLen;
1609 gint res_real = in_plugin->read_probe (&probe_data);
1610 res_real = MAX (1, res_real * GST_TYPE_FIND_MAXIMUM / AVPROBE_SCORE_MAX);
1611 GST_DEBUG ("change res from %d to %d", res, res_real);
1612 res = MAX (res, res_real);
1613 }
1614 #endif
1615 /* Restrict the probability for MPEG-TS streams, because there is
1616 * probably a better version in plugins-base, if the user has a recent
1617 * plugins-base (in fact we shouldn't even get here for ffmpeg mpegts or
1618 * mpegtsraw typefinders, since we blacklist them) */
1619 if (g_str_has_prefix (in_plugin->name, "mpegts"))
1620 res = MIN (res, GST_TYPE_FIND_POSSIBLE);
1621
1622 sinkcaps = gst_ffmpeg_formatid_to_caps (in_plugin->name);
1623
1624 GST_LOG ("libav typefinder '%s' suggests %" GST_PTR_FORMAT ", p=%u%%",
1625 in_plugin->name, sinkcaps, res);
1626
1627 gst_type_find_suggest (tf, res, sinkcaps);
1628 gst_caps_unref (sinkcaps);
1629 }
1630 }
1631 }
1632
1633 /* Task */
1634 static void
1635 gst_ffmpegdemux_loop (GstFFMpegDemux * demux)
1636 {
1637 GstFlowReturn ret;
1638 gint res = -1;
1639 AVPacket pkt;
1640 GstPad *srcpad;
1641 GstFFStream *stream;
1642 AVStream *avstream;
1643 GstBuffer *outbuf = NULL;
1644 GstClockTime timestamp, duration;
1645 gint outsize;
1646 gboolean rawvideo;
1647 GstFlowReturn stream_last_flow;
1648 gint64 pts;
1649
1650 /* open file if we didn't so already */
1651 if (!demux->opened)
1652 if (!gst_ffmpegdemux_open (demux))
1653 goto open_failed;
1654
1655 GST_DEBUG_OBJECT (demux, "about to read a frame");
1656
1657 /* read a frame */
1658 res = av_read_frame (demux->context, &pkt);
1659 if (res < 0)
1660 goto read_failed;
1661
1662 /* get the stream */
1663 stream =
1664 gst_ffmpegdemux_get_stream (demux,
1665 demux->context->streams[pkt.stream_index]);
1666
1667 /* check if we know the stream */
1668 if (stream->unknown)
1669 goto done;
1670
1671 /* get more stuff belonging to this stream */
1672 avstream = stream->avstream;
1673
1674 /* do timestamps, we do this first so that we can know when we
1675 * stepped over the segment stop position. */
1676 pts = pkt.pts;
1677 if (G_UNLIKELY (pts < 0)) {
1678 /* some streams have pts such this:
1679 * 0
1680 * -2
1681 * -1
1682 * 1
1683 *
1684 * we reset pts to 0 since for us timestamp are unsigned
1685 */
1686 GST_WARNING_OBJECT (demux,
1687 "negative pts detected: %" G_GINT64_FORMAT " resetting to 0", pts);
1688 pts = 0;
1689 }
1690 timestamp = gst_ffmpeg_time_ff_to_gst (pts, avstream->time_base);
1691 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1692 stream->last_ts = timestamp;
1693 }
1694 duration = gst_ffmpeg_time_ff_to_gst (pkt.duration, avstream->time_base);
1695 if (G_UNLIKELY (!duration)) {
1696 GST_WARNING_OBJECT (demux, "invalid buffer duration, setting to NONE");
1697 duration = GST_CLOCK_TIME_NONE;
1698 }
1699
1700
1701 GST_DEBUG_OBJECT (demux,
1702 "pkt pts:%" GST_TIME_FORMAT
1703 " / size:%d / stream_index:%d / flags:%d / duration:%" GST_TIME_FORMAT
1704 " / pos:%" G_GINT64_FORMAT, GST_TIME_ARGS (timestamp), pkt.size,
1705 pkt.stream_index, pkt.flags, GST_TIME_ARGS (duration), (gint64) pkt.pos);
1706
1707 /* check start_time */
1708 #if 0
1709 if (demux->start_time != -1 && demux->start_time > timestamp)
1710 goto drop;
1711 #endif
1712
1713 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1714 /* ohos.opt.compat.0002: the demux of gstplayer does not accurately parse audio resources in the aac format.
1715 * As a result, the duration value cannot be obtained in the preparation phase.
1716 * Use the demux and typefind of ffmpeg to process audio resources in aac format.
1717 */
1718 #ifdef OHOS_OPT_COMPAT
1719 if (!(GST_CLOCK_TIME_IS_VALID (demux->start_time)) &&
1720 demux->start_time == -1) {
1721 demux->start_time = timestamp;
1722 }
1723 #endif
1724 /* start_time should be the ts of the first frame but it may actually be
1725 * higher because of rounding when converting to gst ts. */
1726 if (demux->start_time >= timestamp)
1727 timestamp = 0;
1728 else
1729 timestamp -= demux->start_time;
1730 }
1731
1732 /* check if we ran outside of the segment */
1733 if (demux->segment.stop != -1 && timestamp > demux->segment.stop)
1734 goto drop;
1735
1736 /* prepare to push packet to peer */
1737 srcpad = stream->pad;
1738
1739 rawvideo = (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
1740 avstream->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO);
1741
1742 if (rawvideo)
1743 outsize = gst_ffmpeg_avpicture_get_size (avstream->codecpar->format,
1744 avstream->codecpar->width, avstream->codecpar->height);
1745 else
1746 outsize = pkt.size;
1747
1748 outbuf = gst_buffer_new_and_alloc (outsize);
1749
1750 /* copy the data from packet into the target buffer
1751 * and do conversions for raw video packets */
1752 if (rawvideo) {
1753 AVFrame src, dst;
1754 const gchar *plugin_name =
1755 ((GstFFMpegDemuxClass *) (G_OBJECT_GET_CLASS (demux)))->in_plugin->name;
1756 GstMapInfo map;
1757
1758 GST_WARNING ("Unknown demuxer %s, no idea what to do", plugin_name);
1759 gst_ffmpeg_avpicture_fill (&src, pkt.data,
1760 avstream->codecpar->format, avstream->codecpar->width,
1761 avstream->codecpar->height);
1762
1763 gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
1764 gst_ffmpeg_avpicture_fill (&dst, map.data,
1765 avstream->codecpar->format, avstream->codecpar->width,
1766 avstream->codecpar->height);
1767
1768 av_image_copy (dst.data, dst.linesize, (const uint8_t **) src.data,
1769 src.linesize, avstream->codecpar->format, avstream->codecpar->width,
1770 avstream->codecpar->height);
1771 gst_buffer_unmap (outbuf, &map);
1772 } else {
1773 gst_buffer_fill (outbuf, 0, pkt.data, outsize);
1774 }
1775
1776 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1777 GST_BUFFER_DURATION (outbuf) = duration;
1778
1779 /* mark keyframes */
1780 if (!(pkt.flags & AV_PKT_FLAG_KEY)) {
1781 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1782 }
1783
1784 /* Mark discont */
1785 if (stream->discont) {
1786 GST_DEBUG_OBJECT (demux, "marking DISCONT");
1787 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1788 stream->discont = FALSE;
1789 }
1790
1791 GST_DEBUG_OBJECT (demux,
1792 "Sending out buffer time:%" GST_TIME_FORMAT " size:%" G_GSIZE_FORMAT,
1793 GST_TIME_ARGS (timestamp), gst_buffer_get_size (outbuf));
1794
1795 ret = stream_last_flow = gst_pad_push (srcpad, outbuf);
1796
1797 /* if a pad is in e.g. WRONG_STATE, we want to pause to unlock the STREAM_LOCK */
1798 if (((ret = gst_flow_combiner_update_flow (demux->flowcombiner,
1799 ret)) != GST_FLOW_OK)) {
1800 GST_WARNING_OBJECT (demux, "stream_movi flow: %s / %s",
1801 gst_flow_get_name (stream_last_flow), gst_flow_get_name (ret));
1802 goto pause;
1803 }
1804
1805 done:
1806 /* can destroy the packet now */
1807 if (res == 0) {
1808 av_packet_unref (&pkt);
1809 }
1810
1811 return;
1812
1813 /* ERRORS */
1814 pause:
1815 {
1816 GST_LOG_OBJECT (demux, "pausing task, reason %d (%s)", ret,
1817 gst_flow_get_name (ret));
1818 if (demux->seekable)
1819 gst_pad_pause_task (demux->sinkpad);
1820 else {
1821 GstFFMpegPipe *ffpipe = &demux->ffpipe;
1822
1823 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
1824 /* pause task and make sure loop stops */
1825 gst_task_pause (demux->task);
1826 g_rec_mutex_lock (&demux->task_lock);
1827 g_rec_mutex_unlock (&demux->task_lock);
1828 demux->ffpipe.srcresult = ret;
1829 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
1830 }
1831
1832 if (ret == GST_FLOW_EOS) {
1833 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1834 gint64 stop;
1835
1836 if ((stop = demux->segment.stop) == -1)
1837 stop = demux->segment.duration;
1838
1839 GST_LOG_OBJECT (demux, "posting segment done");
1840 gst_element_post_message (GST_ELEMENT (demux),
1841 gst_message_new_segment_done (GST_OBJECT (demux),
1842 demux->segment.format, stop));
1843 gst_ffmpegdemux_push_event (demux,
1844 gst_event_new_segment_done (demux->segment.format, stop));
1845 } else {
1846 GST_LOG_OBJECT (demux, "pushing eos");
1847 gst_ffmpegdemux_push_event (demux, gst_event_new_eos ());
1848 }
1849 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
1850 GST_ELEMENT_FLOW_ERROR (demux, ret);
1851 gst_ffmpegdemux_push_event (demux, gst_event_new_eos ());
1852 }
1853 goto done;
1854 }
1855 open_failed:
1856 {
1857 ret = GST_FLOW_ERROR;
1858 goto pause;
1859 }
1860 read_failed:
1861 {
1862 /* something went wrong... */
1863 GST_WARNING_OBJECT (demux, "av_read_frame returned %d", res);
1864
1865 GST_OBJECT_LOCK (demux);
1866 /* pause appropriatly based on if we are flushing or not */
1867 if (demux->flushing)
1868 ret = GST_FLOW_FLUSHING;
1869 else if (gst_ffmpegdemux_has_outputted (demux)
1870 || gst_ffmpegdemux_is_eos (demux)) {
1871 GST_DEBUG_OBJECT (demux, "We are EOS");
1872 ret = GST_FLOW_EOS;
1873 } else
1874 ret = GST_FLOW_ERROR;
1875 GST_OBJECT_UNLOCK (demux);
1876
1877 goto pause;
1878 }
1879 drop:
1880 {
1881 GST_DEBUG_OBJECT (demux, "dropping buffer out of segment, stream eos");
1882 stream->eos = TRUE;
1883 if (gst_ffmpegdemux_is_eos (demux)) {
1884 av_packet_unref (&pkt);
1885 GST_DEBUG_OBJECT (demux, "we are eos");
1886 ret = GST_FLOW_EOS;
1887 goto pause;
1888 } else {
1889 GST_DEBUG_OBJECT (demux, "some streams are not yet eos");
1890 goto done;
1891 }
1892 }
1893 }
1894
1895 #ifdef OHOS_EXT_FUNC
1896 // ohos.ext.func.0007
1897 static gboolean
1898 gst_ffmpegdemux_is_bytes_segment (GstEvent * event)
1899 {
1900 if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT) {
1901 return FALSE;
1902 }
1903
1904 GstSegment segment;
1905 gst_event_copy_segment(event, &segment);
1906 if (segment.format == GST_FORMAT_BYTES) {
1907 return TRUE;
1908 }
1909
1910 return FALSE;
1911 }
1912 #endif
1913
1914 static gboolean
1915 gst_ffmpegdemux_sink_event (GstPad * sinkpad, GstObject * parent,
1916 GstEvent * event)
1917 {
1918 GstFFMpegDemux *demux;
1919 GstFFMpegPipe *ffpipe;
1920 gboolean result = TRUE;
1921
1922 demux = (GstFFMpegDemux *) parent;
1923 ffpipe = &(demux->ffpipe);
1924
1925 GST_LOG_OBJECT (demux, "event: %" GST_PTR_FORMAT, event);
1926
1927 switch (GST_EVENT_TYPE (event)) {
1928 case GST_EVENT_FLUSH_START:
1929 /* forward event */
1930 gst_pad_event_default (sinkpad, parent, event);
1931
1932 /* now unblock the chain function */
1933 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
1934 ffpipe->srcresult = GST_FLOW_FLUSHING;
1935 GST_FFMPEG_PIPE_SIGNAL (ffpipe);
1936 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
1937
1938 /* loop might run into WRONG_STATE and end itself,
1939 * but may also be waiting in a ffmpeg read
1940 * trying to break that would make ffmpeg believe eos,
1941 * so no harm to have the loop 'pausing' there ... */
1942 goto done;
1943 case GST_EVENT_FLUSH_STOP:
1944 /* forward event */
1945 gst_pad_event_default (sinkpad, parent, event);
1946
1947 GST_OBJECT_LOCK (demux);
1948 g_list_foreach (demux->cached_events, (GFunc) gst_mini_object_unref,
1949 NULL);
1950 g_list_free (demux->cached_events);
1951 GST_OBJECT_UNLOCK (demux);
1952 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
1953 gst_adapter_clear (ffpipe->adapter);
1954 ffpipe->srcresult = GST_FLOW_OK;
1955 /* loop may have decided to end itself as a result of flush WRONG_STATE */
1956 gst_task_start (demux->task);
1957 demux->flushing = FALSE;
1958 GST_LOG_OBJECT (demux, "loop started");
1959 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
1960 goto done;
1961 case GST_EVENT_EOS:
1962 /* inform the src task that it can stop now */
1963 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
1964 ffpipe->eos = TRUE;
1965 GST_FFMPEG_PIPE_SIGNAL (ffpipe);
1966 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
1967
1968 /* eat this event for now, task will send eos when finished */
1969 gst_event_unref (event);
1970 goto done;
1971 case GST_EVENT_STREAM_START:
1972 case GST_EVENT_CAPS:
1973 GST_LOG_OBJECT (demux, "dropping %s event", GST_EVENT_TYPE_NAME (event));
1974 gst_event_unref (event);
1975 goto done;
1976 default:
1977 /* for a serialized event, wait until an earlier data is gone,
1978 * though this is no guarantee as to when task is done with it.
1979 *
1980 * If the demuxer isn't opened, push straight away, since we'll
1981 * be waiting against a cond that will never be signalled. */
1982 if (GST_EVENT_IS_SERIALIZED (event)) {
1983 if (demux->opened) {
1984 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
1985 while (!ffpipe->needed)
1986 GST_FFMPEG_PIPE_WAIT (ffpipe);
1987 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
1988 } else {
1989 #ifdef OHOS_EXT_FUNC
1990 // ohos.ext.func.0007
1991 if (gst_ffmpegdemux_is_bytes_segment(event)) {
1992 GST_DEBUG_OBJECT (demux, "drop segment event: %" GST_PTR_FORMAT, event);
1993 gst_event_unref (event);
1994 goto done;
1995 }
1996 #endif
1997 /* queue events and send them later (esp. tag events) */
1998 GST_OBJECT_LOCK (demux);
1999 demux->cached_events = g_list_append (demux->cached_events, event);
2000 GST_OBJECT_UNLOCK (demux);
2001 goto done;
2002 }
2003 }
2004 break;
2005 }
2006
2007 result = gst_pad_event_default (sinkpad, parent, event);
2008
2009 done:
2010
2011 return result;
2012 }
2013
2014 static GstFlowReturn
2015 gst_ffmpegdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * buffer)
2016 {
2017 GstFFMpegDemux *demux;
2018 GstFFMpegPipe *ffpipe;
2019
2020 demux = (GstFFMpegDemux *) parent;
2021 ffpipe = &demux->ffpipe;
2022
2023 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
2024
2025 if (G_UNLIKELY (ffpipe->eos))
2026 goto eos;
2027
2028 if (G_UNLIKELY (ffpipe->srcresult != GST_FLOW_OK))
2029 goto ignore;
2030
2031 GST_DEBUG ("Giving a buffer of %" G_GSIZE_FORMAT " bytes",
2032 gst_buffer_get_size (buffer));
2033 gst_adapter_push (ffpipe->adapter, buffer);
2034 buffer = NULL;
2035 while (gst_adapter_available (ffpipe->adapter) >= ffpipe->needed) {
2036 GST_DEBUG ("Adapter has more that requested (ffpipe->needed:%d)",
2037 ffpipe->needed);
2038 GST_FFMPEG_PIPE_SIGNAL (ffpipe);
2039 GST_FFMPEG_PIPE_WAIT (ffpipe);
2040 /* may have become flushing */
2041 if (G_UNLIKELY (ffpipe->srcresult != GST_FLOW_OK))
2042 goto ignore;
2043 }
2044
2045 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
2046
2047 return GST_FLOW_OK;
2048
2049 /* special cases */
2050 eos:
2051 {
2052 GST_DEBUG_OBJECT (demux, "ignoring buffer at end-of-stream");
2053 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
2054
2055 gst_buffer_unref (buffer);
2056 return GST_FLOW_EOS;
2057 }
2058 ignore:
2059 {
2060 GST_DEBUG_OBJECT (demux, "ignoring buffer because src task encountered %s",
2061 gst_flow_get_name (ffpipe->srcresult));
2062 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
2063
2064 if (buffer)
2065 gst_buffer_unref (buffer);
2066 return GST_FLOW_FLUSHING;
2067 }
2068 }
2069
2070 static gboolean
2071 gst_ffmpegdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
2072 {
2073 GstQuery *query;
2074 gboolean pull_mode;
2075 #ifndef OHOS_EXT_FUNC
2076 // ohos.ext.func.0007
2077 GstSchedulingFlags flags;
2078 #endif
2079
2080 query = gst_query_new_scheduling ();
2081
2082 if (!gst_pad_peer_query (sinkpad, query)) {
2083 gst_query_unref (query);
2084 goto activate_push;
2085 }
2086
2087 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2088 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2089
2090 #ifndef OHOS_EXT_FUNC
2091 // ohos.ext.func.0007:use pull mode
2092 gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
2093 if (flags & GST_SCHEDULING_FLAG_SEQUENTIAL)
2094 pull_mode = FALSE;
2095 #endif
2096
2097 gst_query_unref (query);
2098
2099 if (!pull_mode)
2100 goto activate_push;
2101
2102 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2103 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2104
2105 activate_push:
2106 {
2107 GST_DEBUG_OBJECT (sinkpad, "activating push");
2108 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2109 }
2110 }
2111
2112 /* push mode:
2113 * - not seekable
2114 * - use gstpipe protocol, like ffmpeg's pipe protocol
2115 * - (independently managed) task driving ffmpeg
2116 */
2117 static gboolean
2118 gst_ffmpegdemux_sink_activate_push (GstPad * sinkpad, GstObject * parent,
2119 gboolean active)
2120 {
2121 GstFFMpegDemux *demux;
2122 gboolean res = FALSE;
2123
2124 demux = (GstFFMpegDemux *) (parent);
2125
2126 if (active) {
2127 if (demux->can_push == FALSE) {
2128 GST_WARNING_OBJECT (demux, "Demuxer can't reliably operate in push-mode");
2129 goto beach;
2130 }
2131 demux->ffpipe.eos = FALSE;
2132 demux->ffpipe.srcresult = GST_FLOW_OK;
2133 demux->ffpipe.needed = 0;
2134 demux->seekable = FALSE;
2135 res = gst_task_start (demux->task);
2136 } else {
2137 GstFFMpegPipe *ffpipe = &demux->ffpipe;
2138
2139 /* release chain and loop */
2140 GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe);
2141 demux->ffpipe.srcresult = GST_FLOW_FLUSHING;
2142 /* end streaming by making ffmpeg believe eos */
2143 demux->ffpipe.eos = TRUE;
2144 GST_FFMPEG_PIPE_SIGNAL (ffpipe);
2145 GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe);
2146
2147 /* make sure streaming ends */
2148 gst_task_stop (demux->task);
2149 g_rec_mutex_lock (&demux->task_lock);
2150 g_rec_mutex_unlock (&demux->task_lock);
2151 res = gst_task_join (demux->task);
2152 demux->seekable = FALSE;
2153 }
2154
2155 beach:
2156 return res;
2157 }
2158
2159 /* pull mode:
2160 * - seekable
2161 * - use gstreamer protocol, like ffmpeg's file protocol
2162 * - task driving ffmpeg based on sink pad
2163 */
2164 static gboolean
2165 gst_ffmpegdemux_sink_activate_pull (GstPad * sinkpad, GstObject * parent,
2166 gboolean active)
2167 {
2168 GstFFMpegDemux *demux;
2169 gboolean res;
2170
2171 demux = (GstFFMpegDemux *) parent;
2172
2173 if (active) {
2174 demux->seekable = TRUE;
2175 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ffmpegdemux_loop,
2176 demux, NULL);
2177 } else {
2178 res = gst_pad_stop_task (sinkpad);
2179 demux->seekable = FALSE;
2180 }
2181
2182 return res;
2183 }
2184
2185 static gboolean
2186 gst_ffmpegdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2187 GstPadMode mode, gboolean active)
2188 {
2189 gboolean res;
2190
2191 switch (mode) {
2192 case GST_PAD_MODE_PUSH:
2193 res = gst_ffmpegdemux_sink_activate_push (sinkpad, parent, active);
2194 break;
2195 case GST_PAD_MODE_PULL:
2196 res = gst_ffmpegdemux_sink_activate_pull (sinkpad, parent, active);
2197 break;
2198 default:
2199 res = FALSE;
2200 break;
2201 }
2202 return res;
2203 }
2204
2205 static GstStateChangeReturn
2206 gst_ffmpegdemux_change_state (GstElement * element, GstStateChange transition)
2207 {
2208 GstFFMpegDemux *demux = (GstFFMpegDemux *) (element);
2209 GstStateChangeReturn ret;
2210
2211 switch (transition) {
2212 case GST_STATE_CHANGE_READY_TO_PAUSED:
2213 #if 0
2214 /* test seek in READY here */
2215 gst_element_send_event (element, gst_event_new_seek (1.0,
2216 GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
2217 GST_SEEK_TYPE_SET, 10 * GST_SECOND,
2218 GST_SEEK_TYPE_SET, 13 * GST_SECOND));
2219 #endif
2220 break;
2221 default:
2222 break;
2223 }
2224
2225 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2226
2227 switch (transition) {
2228 case GST_STATE_CHANGE_PAUSED_TO_READY:
2229 gst_ffmpegdemux_close (demux);
2230 gst_adapter_clear (demux->ffpipe.adapter);
2231 g_list_foreach (demux->cached_events, (GFunc) gst_mini_object_unref,
2232 NULL);
2233 g_list_free (demux->cached_events);
2234 demux->cached_events = NULL;
2235 demux->have_group_id = FALSE;
2236 demux->group_id = G_MAXUINT;
2237 break;
2238 default:
2239 break;
2240 }
2241
2242 return ret;
2243 }
2244
2245 gboolean
2246 gst_ffmpegdemux_register (GstPlugin * plugin)
2247 {
2248 GType type;
2249 const AVInputFormat *in_plugin;
2250 gchar *extensions;
2251 GTypeInfo typeinfo = {
2252 sizeof (GstFFMpegDemuxClass),
2253 (GBaseInitFunc) gst_ffmpegdemux_base_init,
2254 NULL,
2255 (GClassInitFunc) gst_ffmpegdemux_class_init,
2256 NULL,
2257 NULL,
2258 sizeof (GstFFMpegDemux),
2259 0,
2260 (GInstanceInitFunc) gst_ffmpegdemux_init,
2261 };
2262
2263 void *i = 0;
2264
2265 GST_LOG ("Registering demuxers");
2266
2267 while ((in_plugin = av_demuxer_iterate (&i))) {
2268 gchar *type_name, *typefind_name;
2269 gint rank;
2270 gboolean register_typefind_func = TRUE;
2271
2272 GST_LOG ("Attempting to handle libav demuxer plugin %s [%s]",
2273 in_plugin->name, in_plugin->long_name);
2274
2275 /* no emulators */
2276 /* ohos.opt.compat.0002 */
2277 #ifdef OHOS_OPT_COMPAT
2278 if(in_plugin->long_name != NULL && strncmp (in_plugin->name, "aac", 4)) {
2279 #else
2280 if(in_plugin->long_name != NULL) {
2281 #endif
2282 if (!strncmp (in_plugin->long_name, "raw ", 4) ||
2283 !strncmp (in_plugin->long_name, "pcm ", 4)
2284 )
2285 continue;
2286 }
2287
2288 if (!strcmp (in_plugin->name, "audio_device") ||
2289 !strncmp (in_plugin->name, "image", 5) ||
2290 !strcmp (in_plugin->name, "mpegvideo") ||
2291 !strcmp (in_plugin->name, "mjpeg") ||
2292 !strcmp (in_plugin->name, "redir") ||
2293 !strncmp (in_plugin->name, "u8", 2) ||
2294 !strncmp (in_plugin->name, "u16", 3) ||
2295 !strncmp (in_plugin->name, "u24", 3) ||
2296 !strncmp (in_plugin->name, "u32", 3) ||
2297 !strncmp (in_plugin->name, "s8", 2) ||
2298 !strncmp (in_plugin->name, "s16", 3) ||
2299 !strncmp (in_plugin->name, "s24", 3) ||
2300 !strncmp (in_plugin->name, "s32", 3) ||
2301 !strncmp (in_plugin->name, "f32", 3) ||
2302 !strncmp (in_plugin->name, "f64", 3) ||
2303 !strcmp (in_plugin->name, "mulaw") || !strcmp (in_plugin->name, "alaw")
2304 )
2305 continue;
2306
2307 /* no network demuxers */
2308 if (!strcmp (in_plugin->name, "sdp") ||
2309 !strcmp (in_plugin->name, "rtsp") ||
2310 !strcmp (in_plugin->name, "applehttp")
2311 )
2312 continue;
2313
2314 /* these don't do what one would expect or
2315 * are only partially functional/useful */
2316 if (!strcmp (in_plugin->name, "wv") ||
2317 /* ohos.opt.compat.0002: the demux of gstplayer does not accurately parse audio resources in the aac format.
2318 * As a result, the duration value cannot be obtained in the preparation phase.
2319 * Use the demux and typefind of ffmpeg to process audio resources in aac format.
2320 */
2321 #ifndef OHOS_OPT_COMPAT
2322 !strcmp (in_plugin->name, "aac") ||
2323 #endif
2324 !strcmp (in_plugin->name, "ass") ||
2325 !strcmp (in_plugin->name, "ffmetadata"))
2326 continue;
2327
2328 /* Don't use the typefind functions of formats for which we already have
2329 * better typefind functions */
2330 if (!strcmp (in_plugin->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
2331 !strcmp (in_plugin->name, "ass") ||
2332 !strcmp (in_plugin->name, "avi") ||
2333 !strcmp (in_plugin->name, "asf") ||
2334 !strcmp (in_plugin->name, "mpegvideo") ||
2335 /* ohos.opt.compat.0001: The demux of gstplayer does not accurately parse audio resources in the MP3 format.
2336 * As a result, the duration value cannot be obtained in the preparation phase.
2337 * Use the demux and typefind of ffmpeg to process audio resources in MP3 format.
2338 */
2339 #ifndef OHOS_OPT_COMPAT
2340 !strcmp (in_plugin->name, "mp3") ||
2341 #endif
2342 !strcmp (in_plugin->name, "matroska") ||
2343 !strcmp (in_plugin->name, "matroska_webm") ||
2344 !strcmp (in_plugin->name, "matroska,webm") ||
2345 !strcmp (in_plugin->name, "mpeg") ||
2346 !strcmp (in_plugin->name, "wav") ||
2347 !strcmp (in_plugin->name, "au") ||
2348 !strcmp (in_plugin->name, "tta") ||
2349 !strcmp (in_plugin->name, "rm") ||
2350 !strcmp (in_plugin->name, "amr") ||
2351 !strcmp (in_plugin->name, "ogg") ||
2352 !strcmp (in_plugin->name, "aiff") ||
2353 !strcmp (in_plugin->name, "ape") ||
2354 !strcmp (in_plugin->name, "dv") ||
2355 !strcmp (in_plugin->name, "flv") ||
2356 !strcmp (in_plugin->name, "mpc") ||
2357 !strcmp (in_plugin->name, "mpc8") ||
2358 !strcmp (in_plugin->name, "mpegts") ||
2359 !strcmp (in_plugin->name, "mpegtsraw") ||
2360 !strcmp (in_plugin->name, "mxf") ||
2361 !strcmp (in_plugin->name, "nuv") ||
2362 !strcmp (in_plugin->name, "swf") ||
2363 !strcmp (in_plugin->name, "voc") ||
2364 !strcmp (in_plugin->name, "pva") ||
2365 !strcmp (in_plugin->name, "gif") ||
2366 !strcmp (in_plugin->name, "vc1test") ||
2367 !strcmp (in_plugin->name, "ivf"))
2368 register_typefind_func = FALSE;
2369
2370 /* Set the rank of demuxers known to work to MARGINAL.
2371 * Set demuxers for which we already have another implementation to NONE
2372 * Set All others to NONE*/
2373 /**
2374 * element-avdemux_xwma
2375 *
2376 * Since: 1.20
2377 */
2378 if (!strcmp (in_plugin->name, "wsvqa") ||
2379 !strcmp (in_plugin->name, "wsaud") ||
2380 !strcmp (in_plugin->name, "wc3movie") ||
2381 !strcmp (in_plugin->name, "voc") ||
2382 !strcmp (in_plugin->name, "tta") ||
2383 !strcmp (in_plugin->name, "sol") ||
2384 !strcmp (in_plugin->name, "smk") ||
2385 !strcmp (in_plugin->name, "vmd") ||
2386 !strcmp (in_plugin->name, "film_cpk") ||
2387 !strcmp (in_plugin->name, "ingenient") ||
2388 !strcmp (in_plugin->name, "psxstr") ||
2389 !strcmp (in_plugin->name, "nuv") ||
2390 !strcmp (in_plugin->name, "nut") ||
2391 !strcmp (in_plugin->name, "nsv") ||
2392 !strcmp (in_plugin->name, "mxf") ||
2393 !strcmp (in_plugin->name, "mmf") ||
2394 !strcmp (in_plugin->name, "mm") ||
2395 !strcmp (in_plugin->name, "ipmovie") ||
2396 !strcmp (in_plugin->name, "ape") ||
2397 !strcmp (in_plugin->name, "RoQ") ||
2398 !strcmp (in_plugin->name, "idcin") ||
2399 !strcmp (in_plugin->name, "gxf") ||
2400 !strcmp (in_plugin->name, "ffm") ||
2401 !strcmp (in_plugin->name, "ea") ||
2402 !strcmp (in_plugin->name, "daud") ||
2403 /* ohos.opt.compat.0001: add avdemux_ogg
2404 * add avdemux_mp3
2405 * ohos.opt.compat.0002: add avdemux_aac */
2406 #ifdef OHOS_OPT_COMPAT
2407 /* enable to use avdemux_ogg */
2408 !strcmp (in_plugin->name, "ogg") ||
2409 /* enable to use avdemux_mp3 */
2410 !strcmp (in_plugin->name, "mp3") ||
2411 /*enable to use avdemux_aac*/
2412 !strcmp (in_plugin->name, "aac") ||
2413 #endif
2414 !strcmp (in_plugin->name, "avs") ||
2415 !strcmp (in_plugin->name, "aiff") ||
2416 !strcmp (in_plugin->name, "xwma") ||
2417 !strcmp (in_plugin->name, "4xm") ||
2418 !strcmp (in_plugin->name, "yuv4mpegpipe") ||
2419 !strcmp (in_plugin->name, "pva") ||
2420 !strcmp (in_plugin->name, "mpc") ||
2421 !strcmp (in_plugin->name, "mpc8") ||
2422 !strcmp (in_plugin->name, "ivf") ||
2423 !strcmp (in_plugin->name, "brstm") ||
2424 !strcmp (in_plugin->name, "bfstm") ||
2425 !strcmp (in_plugin->name, "gif") ||
2426 !strcmp (in_plugin->name, "dsf") || !strcmp (in_plugin->name, "iff"))
2427 rank = GST_RANK_MARGINAL;
2428 else {
2429 GST_DEBUG ("ignoring %s", in_plugin->name);
2430 rank = GST_RANK_NONE;
2431 continue;
2432 }
2433
2434 /* construct the type */
2435 type_name = g_strdup_printf ("avdemux_%s", in_plugin->name);
2436 g_strdelimit (type_name, ".,|-<> ", '_');
2437
2438 /* if it's already registered, drop it */
2439 if (g_type_from_name (type_name)) {
2440 g_free (type_name);
2441 continue;
2442 }
2443
2444 typefind_name = g_strdup_printf ("avtype_%s", in_plugin->name);
2445 g_strdelimit (typefind_name, ".,|-<> ", '_');
2446
2447 /* create the type now */
2448 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
2449 g_type_set_qdata (type, GST_FFDEMUX_PARAMS_QDATA, (gpointer) in_plugin);
2450
2451 if (in_plugin->extensions)
2452 extensions = g_strdelimit (g_strdup (in_plugin->extensions), " ", ',');
2453 else
2454 extensions = NULL;
2455
2456 if (!gst_element_register (plugin, type_name, rank, type) ||
2457 (register_typefind_func == TRUE &&
2458 !gst_type_find_register (plugin, typefind_name, rank,
2459 gst_ffmpegdemux_type_find, extensions, NULL,
2460 (gpointer) in_plugin, NULL))) {
2461 g_warning ("Registration of type %s failed", type_name);
2462 g_free (type_name);
2463 g_free (typefind_name);
2464 g_free (extensions);
2465 return FALSE;
2466 }
2467
2468 g_free (type_name);
2469 g_free (typefind_name);
2470 g_free (extensions);
2471 }
2472
2473 GST_LOG ("Finished registering demuxers");
2474
2475 return TRUE;
2476 }
2477