• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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