2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
26 #include <libavformat/avformat.h>
27 #include <libavutil/opt.h>
29 #include <gst/base/gstcollectpads.h>
32 #include "gstavcodecmap.h"
33 #include "gstavutils.h"
34 #include "gstavprotocol.h"
36 #ifdef TIZEN_FEATURE_LIBAV
37 #include "libavformat/movenc.h"
38 #include "libavformat/internal.h"
39 #endif /* TIZEN_FEATURE_LIBAV */
41 typedef struct _GstFFMpegMux GstFFMpegMux;
42 typedef struct _GstFFMpegMuxPad GstFFMpegMuxPad;
44 struct _GstFFMpegMuxPad
46 GstCollectData collect; /* we extend the CollectData */
55 GstCollectPads *collect;
56 /* We need to keep track of our pads, so we do so here. */
59 AVFormatContext *context;
62 guint videopads, audiopads;
63 #ifdef TIZEN_FEATURE_LIBAV
64 guint expected_trailer_size;
65 guint nb_video_frames;
66 guint nb_audio_frames;
67 #endif /* TIZEN_FEATURE_LIBAV */
70 /* event_function is the collectpads default eventfunction */
71 GstPadEventFunction event_function;
76 typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
78 struct _GstFFMpegMuxClass
80 GstElementClass parent_class;
82 AVOutputFormat *in_plugin;
85 #define GST_TYPE_FFMPEGMUX \
86 (gst_ffmpegdec_get_type())
87 #define GST_FFMPEGMUX(obj) \
88 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGMUX,GstFFMpegMux))
89 #define GST_FFMPEGMUX_CLASS(klass) \
90 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGMUX,GstFFMpegMuxClass))
91 #define GST_IS_FFMPEGMUX(obj) \
92 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGMUX))
93 #define GST_IS_FFMPEGMUX_CLASS(klass) \
94 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGMUX))
107 #ifdef TIZEN_FEATURE_LIBAV
108 , PROP_EXPECTED_TRAILER_SIZE,
109 PROP_NUMBER_VIDEO_FRAMES,
110 PROP_NUMBER_AUDIO_FRAMES
111 #endif /* TIZEN_FEATURE_LIBAV */
114 /* A number of function prototypes are given so we can refer to them later. */
115 static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass);
116 static void gst_ffmpegmux_base_init (gpointer g_class);
117 static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux,
118 GstFFMpegMuxClass * g_class);
119 static void gst_ffmpegmux_finalize (GObject * object);
121 static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstObject * parent,
123 static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
124 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
125 static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads,
128 static gboolean gst_ffmpegmux_sink_event (GstPad * pad, GstObject * parent,
131 static GstStateChangeReturn gst_ffmpegmux_change_state (GstElement * element,
132 GstStateChange transition);
134 static void gst_ffmpegmux_set_property (GObject * object, guint prop_id,
135 const GValue * value, GParamSpec * pspec);
136 static void gst_ffmpegmux_get_property (GObject * object, guint prop_id,
137 GValue * value, GParamSpec * pspec);
139 static GstCaps *gst_ffmpegmux_get_id_caps (enum AVCodecID *id_list);
140 static void gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps,
141 const gchar * field, guint num, const gint * values);
143 #define GST_FFMUX_PARAMS_QDATA g_quark_from_static_string("avmux-params")
145 #ifdef TIZEN_FEATURE_LIBAV
146 static void gst_ffmpegmux_release_pad(GstElement *element, GstPad *pad);
147 #endif /* TIZEN_FEATURE_LIBAV */
149 static GstElementClass *parent_class = NULL;
151 /*static guint gst_ffmpegmux_signals[LAST_SIGNAL] = { 0 }; */
156 const char *replacement;
157 } GstFFMpegMuxReplacement;
160 gst_ffmpegmux_get_replacement (const char *name)
162 static const GstFFMpegMuxReplacement blacklist[] = {
164 {"matroska", "matroskamux"},
166 {"mpegts", "mpegtsmux"},
168 {"mpjpeg", "multipartmux"},
174 {"yuv4mpegpipe", "y4menc"},
176 {"adts", "aacparse"},
178 {"asf_stream", "asfmux"},
185 for (i = 0; i < sizeof (blacklist) / sizeof (blacklist[0]); i++) {
186 if (strcmp (blacklist[i].name, name) == 0) {
187 return blacklist[i].replacement;
195 gst_ffmpegmux_is_formatter (const char *name)
197 static const char *replace[] = {
202 for (i = 0; replace[i]; i++)
203 if (strcmp (replace[i], name) == 0)
208 #ifdef TIZEN_FEATURE_LIBAV
209 /* trailer entry size */
210 #define ENTRY_SIZE_VIDEO_STTS 8
211 #define ENTRY_SIZE_VIDEO_STSS 4
212 #define ENTRY_SIZE_VIDEO_STSZ 4
213 #define ENTRY_SIZE_VIDEO_STCO 4
214 #define ENTRY_SIZE_AUDIO_STTS 8
215 #define ENTRY_SIZE_AUDIO_STSZ 4
216 #define ENTRY_SIZE_AUDIO_STCO 4
218 #define ENTRY_SIZE_VIDEO_MPEG4_STSD 146
219 #define ENTRY_SIZE_VIDEO_H263P_STSD 102
220 #define ENTRY_SIZE_AUDIO_AAC_STSD 106
221 #define ENTRY_SIZE_AUDIO_AMR_STSD 69
223 #define ENTRY_SIZE_STSC 12
224 #define ENTRY_SIZE_VIDEO_ST 84 /*atom size (stss + stts + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
225 #define ENTRY_SIZE_AUDIO_ST 68 /*atom size (stss + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
228 #define MUX_ADTS_NAME "adts"
229 #define MUX_AMR_NAME "amr"
230 #define MUX_MP4_NAME "mp4"
231 #define MUX_ADTS_SIZE_HEADER 8
232 #define MUX_ADTS_SIZE_ENTRY 7
233 #define MUX_AMR_SIZE_HEADER 6
236 #define MUX_COMMON_SIZE_3GP_HEADER 290 /* ftyp + free + moov + mvhd + +iods + udta */
237 #define MUX_COMMON_SIZE_MP4_HEADER 378 /* ftyp + free + moov + mvhd + +iods + udta (meta) */
238 #define MUX_COMMON_SIZE_MP4_VIDEO_HEADER 305
239 #define MUX_COMMON_SIZE_MP4_AUDIO_HEADER 253
241 #define MUX_INFO_SIZE_LOCATION 106 /* loci + .xyz */
244 update_expected_trailer_size (GstFFMpegMux * ffmpegmux)
247 guint nb_video_frames = 0;
248 guint nb_video_i_frames = 0;
249 guint nb_video_stts_entry = 0;
250 guint nb_audio_frames = 0;
251 guint nb_audio_stts_entry = 0;
252 gboolean video_stream = FALSE;
253 gboolean audio_stream = FALSE;
255 AVCodecParameters *codec_context = NULL;
256 FFStream *sti = NULL;
257 enum AVCodecID video_codec_id;
258 enum AVCodecID audio_codec_id;
260 if (ffmpegmux == NULL) {
261 GST_WARNING ("ffmpegmux is NULL");
265 for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
266 sti = ffstream(ffmpegmux->context->streams[i]);
267 codec_context = ffmpegmux->context->streams[i]->codecpar;
268 if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO) {
269 nb_video_frames += sti->avctx->frame_number;
270 nb_video_i_frames += codec_context->i_frame_number;
271 nb_video_stts_entry += codec_context->stts_count;
274 video_codec_id = codec_context->codec_id;
275 } else if (codec_context->codec_type == AVMEDIA_TYPE_AUDIO) {
276 nb_audio_frames += sti->avctx->frame_number;
277 nb_audio_stts_entry += codec_context->stts_count;
280 audio_codec_id = codec_context->codec_id;
287 ftyp = 28 (MPEG4 ftype: 28 , H263P fype: 28)
293 udta = 114(meta in case of audio only) or
294 114(loci in case of video only or video/audio) or
295 202( with meta in MP4)
296 96 ( audio only with meta )
298 total : 290 (3GP) or 378 (MP4)
303 edts = 48 ( addition )
309 dinf = 36 ( 8 , dref : 16 , url : 12 )
310 stbl = 8 ( common video total : 305 )
311 stsd = 146 ( addtion : 16 + , mp4v: 86 ,esds : 44 )
312 stts = 16 + (8*stts_count)
313 stss = 16 + (4*I-frame)
315 stsz = 20 + (4*frame)
316 stco = 16 + (4*frame)
318 - VIDEO:H.264 = 487(or 489) + (8*stts_count) + (8*frame) + (4*I-frame)
321 edts = 48 ( addition )
327 dinf = 36 ( 8 , dref : 16 , url : 12 )
329 stsd = 134 (SPS 9, PPS 4) or 136 (SPS 111, PPS 4)
330 stts = 16 + (8*stts_count)
331 stss = 16 + (4*I-frame)
333 stsz = 20 + (4*frame)
334 stco = 16 + (4*frame)
336 - VIDEO:H.263 = 470 + + (8*stts_count) + (8*frame) + (4*I-frame)
339 edts = 48 ( addition )
347 stsd = 102 -> different from H.264
348 stts = 16 + (8*stts_count)
349 stss = 16 + (4*I-frame)
351 stsz = 20 + (4*frame)
352 stco = 16 + (4*frame)
354 - AUDIO:AAC = 424 + + (8*stts_count) + (8*audio_frame)
362 dinf = 36 ( 8 , dref : 16 , url : 12 )
363 stbl = 8 ( common video total : 253 )
364 stsd = 106 + ( addtion : 16 , mp4v: 46 ,esds : 54 )
365 stts = 16 + (8*stts_count)
367 stsz = 20 + (4*frame)
368 stco = 16 + (4*frame)
370 - AUDIO:AMR = 410 + (4*audio_frame)
380 stsd = 69 -> different from AAC
381 stts = 24 -> different from AAC
383 stsz = 20 -> different from AAC
384 stco = 16 + (4*frame)
387 /* Calculate trailer size for video stream */
388 if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
390 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
392 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_MP4_NAME)) {
393 exp_size = MUX_COMMON_SIZE_MP4_HEADER;
395 exp_size = MUX_COMMON_SIZE_3GP_HEADER;
397 //GST_INFO_OBJECT(ffmpegmux, "size: common size=[%d]", exp_size);
400 /* ftyp + free + moov + mvhd + udta : H.264 -> 240, H.263 -> 236 */
401 /* trak size except frame related : H.264 -> 489, H.263 -> 470 */
402 if (video_codec_id == AV_CODEC_ID_H263
403 || video_codec_id == AV_CODEC_ID_H263P) {
405 MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_H263P_STSD;
406 } else if (video_codec_id == AV_CODEC_ID_MPEG4) {
408 MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_MPEG4_STSD;
410 exp_size += 240 + 489;
413 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
417 ENTRY_SIZE_VIDEO_ST + (ENTRY_SIZE_VIDEO_STTS * nb_video_stts_entry) +
418 (ENTRY_SIZE_VIDEO_STSS * nb_video_i_frames) + (ENTRY_SIZE_STSC) +
419 ((ENTRY_SIZE_VIDEO_STSZ + ENTRY_SIZE_VIDEO_STCO) * nb_video_frames);
421 //GST_INFO_OBJECT(ffmpegmux, "size: video=[%d] size=[%d], stts-entry=[%d], i-frame=[%d], video-sample=[%d]", video_stream, exp_size,nb_video_stts_entry,nb_video_i_frames,nb_video_frames);
424 /* Calculate trailer size for audio stream */
425 if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
428 MUX_ADTS_SIZE_HEADER + (MUX_ADTS_SIZE_ENTRY * nb_audio_frames);
429 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_AMR_NAME)) {
430 /* only audio avmux_amr */
431 exp_size = MUX_AMR_SIZE_HEADER;
433 /* avmux_3gp , avmux_mp4 */
435 /* audio only does not contain location info now */
436 exp_size -= MUX_INFO_SIZE_LOCATION;
438 /* others - avmux_3gp/mp4/amr */
439 if (audio_codec_id == AV_CODEC_ID_AMR_NB) {
442 MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AMR_STSD;
444 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
447 ENTRY_SIZE_AUDIO_ST +
448 (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
449 (ENTRY_SIZE_AUDIO_STCO * nb_audio_frames);
453 MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AAC_STSD;
455 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
458 ENTRY_SIZE_AUDIO_ST +
459 (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
460 ((ENTRY_SIZE_AUDIO_STSZ + ENTRY_SIZE_AUDIO_STCO) * nb_audio_frames);
465 //GST_INFO_OBJECT(ffmpegmux, "size: audio=[%d], size=[%d], stts-entry=[%d], audio-sample=[%d]", audio_stream, exp_size, nb_audio_stts_entry, nb_audio_frames);
467 ffmpegmux->expected_trailer_size = exp_size;
468 ffmpegmux->nb_video_frames = nb_video_frames;
469 ffmpegmux->nb_audio_frames = nb_audio_frames;
473 #endif /* TIZEN_FEATURE_LIBAV */
476 gst_ffmpegmux_base_init (gpointer g_class)
478 GstFFMpegMuxClass *klass = (GstFFMpegMuxClass *) g_class;
479 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
480 GstPadTemplate *videosinktempl, *audiosinktempl, *srctempl;
481 AVOutputFormat *in_plugin;
482 GstCaps *srccaps, *audiosinkcaps, *videosinkcaps;
483 enum AVCodecID *video_ids = NULL, *audio_ids = NULL;
484 gchar *longname, *description, *name;
485 const char *replacement;
486 gboolean is_formatter;
489 (AVOutputFormat *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
490 GST_FFMUX_PARAMS_QDATA);
491 g_assert (in_plugin != NULL);
493 name = g_strdup (in_plugin->name);
494 g_strdelimit (name, ".,|-<> ", '_');
496 /* construct the element details struct */
497 replacement = gst_ffmpegmux_get_replacement (in_plugin->name);
498 is_formatter = gst_ffmpegmux_is_formatter (in_plugin->name);
499 if (replacement != NULL) {
501 g_strdup_printf ("libav %s %s (not recommended, use %s instead)",
502 in_plugin->long_name, is_formatter ? "formatter" : "muxer",
505 g_strdup_printf ("libav %s %s (not recommended, use %s instead)",
506 in_plugin->long_name, is_formatter ? "formatter" : "muxer",
509 longname = g_strdup_printf ("libav %s %s", in_plugin->long_name,
510 is_formatter ? "formatter" : "muxer");
511 description = g_strdup_printf ("libav %s %s", in_plugin->long_name,
512 is_formatter ? "formatter" : "muxer");
514 gst_element_class_set_metadata (element_class, longname,
515 is_formatter ? "Formatter/Metadata" : "Codec/Muxer", description,
516 "Wim Taymans <wim.taymans@chello.be>, "
517 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
519 g_free (description);
521 /* Try to find the caps that belongs here */
522 srccaps = gst_ffmpeg_formatid_to_caps (name);
524 GST_DEBUG ("Couldn't get source caps for muxer '%s', skipping", name);
528 if (!gst_ffmpeg_formatid_get_codecids (in_plugin->name,
529 &video_ids, &audio_ids, in_plugin)) {
530 gst_caps_unref (srccaps);
531 GST_DEBUG ("Couldn't get sink caps for muxer '%s'. Most likely because "
532 "no input format mapping exists.", name);
536 videosinkcaps = video_ids ? gst_ffmpegmux_get_id_caps (video_ids) : NULL;
537 audiosinkcaps = audio_ids ? gst_ffmpegmux_get_id_caps (audio_ids) : NULL;
539 /* fix up allowed caps for some muxers */
540 /* FIXME : This should be in gstffmpegcodecmap.c ! */
541 if (strcmp (in_plugin->name, "flv") == 0) {
542 const gint rates[] = { 44100, 22050, 11025 };
544 gst_ffmpeg_mux_simple_caps_set_int_list (audiosinkcaps, "rate", 3, rates);
545 } else if (strcmp (in_plugin->name, "dv") == 0) {
546 gst_caps_set_simple (audiosinkcaps,
547 "rate", G_TYPE_INT, 48000, "channels", G_TYPE_INT, 2, NULL);
552 srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
553 gst_element_class_add_pad_template (element_class, srctempl);
554 gst_caps_unref (srccaps);
557 audiosinktempl = gst_pad_template_new ("audio_%u",
558 GST_PAD_SINK, GST_PAD_REQUEST, audiosinkcaps);
559 gst_element_class_add_pad_template (element_class, audiosinktempl);
560 gst_caps_unref (audiosinkcaps);
564 videosinktempl = gst_pad_template_new ("video_%u",
565 GST_PAD_SINK, GST_PAD_REQUEST, videosinkcaps);
566 gst_element_class_add_pad_template (element_class, videosinktempl);
567 gst_caps_unref (videosinkcaps);
571 klass->in_plugin = in_plugin;
577 gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
579 GObjectClass *gobject_class;
580 GstElementClass *gstelement_class;
581 #ifdef TIZEN_FEATURE_LIBAV
582 GParamSpec * tspec = NULL;
583 #endif /* TIZEN_FEATURE_LIBAV */
585 gobject_class = (GObjectClass *) klass;
586 gstelement_class = (GstElementClass *) klass;
588 parent_class = g_type_class_peek_parent (klass);
590 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_set_property);
591 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_get_property);
593 g_object_class_install_property (gobject_class, PROP_PRELOAD,
594 g_param_spec_int ("preload", "preload",
595 "Set the initial demux-decode delay (in microseconds)",
596 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
598 g_object_class_install_property (gobject_class, PROP_MAXDELAY,
599 g_param_spec_int ("maxdelay", "maxdelay",
600 "Set the maximum demux-decode delay (in microseconds)", 0, G_MAXINT,
601 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
603 gstelement_class->request_new_pad = gst_ffmpegmux_request_new_pad;
604 gstelement_class->change_state = gst_ffmpegmux_change_state;
605 gobject_class->finalize = gst_ffmpegmux_finalize;
607 #ifdef TIZEN_FEATURE_LIBAV
608 gstelement_class->release_pad = gst_ffmpegmux_release_pad;
611 tspec = g_param_spec_uint("expected-trailer-size", "Expected Trailer Size",
612 "Expected trailer size (bytes)",
613 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
615 g_object_class_install_property(gobject_class, PROP_EXPECTED_TRAILER_SIZE, tspec);
617 GST_ERROR("g_param_spec failed for \"expected-trailer-size\"");
619 tspec = g_param_spec_uint("number-video-frames", "Number of video frames",
620 "Current number of video frames",
621 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
623 g_object_class_install_property (gobject_class, PROP_NUMBER_VIDEO_FRAMES, tspec);
625 GST_ERROR("g_param_spec failed for \"number-video-frames\"");
627 tspec = g_param_spec_uint("number-audio-frames", "Number of audio frames",
628 "Current number of audio frames",
629 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
631 g_object_class_install_property (gobject_class, PROP_NUMBER_AUDIO_FRAMES, tspec);
633 GST_ERROR("g_param_spec failed for \"number-audio-frames\"");
634 #endif /* TIZEN_FEATURE_LIBAV */
638 gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux, GstFFMpegMuxClass * g_class)
640 GstElementClass *klass = GST_ELEMENT_CLASS (g_class);
641 GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass *) klass;
642 GstPadTemplate *templ = gst_element_class_get_pad_template (klass, "src");
644 ffmpegmux->srcpad = gst_pad_new_from_template (templ, "src");
645 gst_pad_set_caps (ffmpegmux->srcpad, gst_pad_template_get_caps (templ));
646 gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->srcpad);
648 ffmpegmux->collect = gst_collect_pads_new ();
649 gst_collect_pads_set_function (ffmpegmux->collect,
650 (GstCollectPadsFunction) gst_ffmpegmux_collected, ffmpegmux);
652 ffmpegmux->context = avformat_alloc_context ();
653 ffmpegmux->context->oformat = oclass->in_plugin;
654 ffmpegmux->context->nb_streams = 0;
655 ffmpegmux->opened = FALSE;
657 ffmpegmux->videopads = 0;
658 ffmpegmux->audiopads = 0;
659 ffmpegmux->max_delay = 0;
661 #ifdef TIZEN_FEATURE_LIBAV
662 ffmpegmux->expected_trailer_size = 0;
663 ffmpegmux->nb_video_frames = 0;
664 ffmpegmux->nb_audio_frames = 0;
665 #endif /* TIZEN_FEATURE_LIBAV */
668 #ifdef TIZEN_FEATURE_LIBAV
670 gst_ffmpegmux_release_pad (GstElement * element, GstPad * pad)
672 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
673 GstFFMpegMuxPad *collect_pad;
676 collect_pad = (GstFFMpegMuxPad *)gst_pad_get_element_private(pad);
678 GST_DEBUG ("Release requested pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
679 st = ffmpegmux->context->streams[collect_pad->padnum];
682 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
683 ffmpegmux->videopads--;
685 ffmpegmux->audiopads--;
687 if (st->codecpar->extradata) {
688 av_free(st->codecpar->extradata);
689 st->codecpar->extradata = NULL;
691 g_free(st->codecpar);
694 if (ffmpegmux->context->priv_data) {
695 MOVMuxContext *mov = ffmpegmux->context->priv_data;
696 if (mov && mov->tracks) {
697 for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
698 MOVTrack *trk = &mov->tracks[i];
699 if (trk && trk->vos_data) {
700 av_free(trk->vos_data);
701 trk->vos_data = NULL;
704 av_free(mov->tracks);
707 av_free(ffmpegmux->context->priv_data);
708 ffmpegmux->context->priv_data = NULL;
710 ffmpegmux->context->nb_streams--;
714 gst_collect_pads_remove_pad(ffmpegmux->collect, pad);
715 gst_element_remove_pad(element, pad);
717 #endif /* TIZEN_FEATURE_LIBAV */
720 gst_ffmpegmux_set_property (GObject * object, guint prop_id,
721 const GValue * value, GParamSpec * pspec)
725 src = (GstFFMpegMux *) object;
729 src->preload = g_value_get_int (value);
732 src->max_delay = g_value_get_int (value);
735 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
741 gst_ffmpegmux_get_property (GObject * object, guint prop_id, GValue * value,
746 src = (GstFFMpegMux *) object;
750 g_value_set_int (value, src->preload);
753 g_value_set_int (value, src->max_delay);
755 #ifdef TIZEN_FEATURE_LIBAV
756 case PROP_EXPECTED_TRAILER_SIZE:
757 g_value_set_uint(value, src->expected_trailer_size);
759 case PROP_NUMBER_VIDEO_FRAMES:
760 g_value_set_uint(value, src->nb_video_frames);
762 case PROP_NUMBER_AUDIO_FRAMES:
763 g_value_set_uint(value, src->nb_audio_frames);
765 #endif /* TIZEN_FEATURE_LIBAV */
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
774 gst_ffmpegmux_finalize (GObject * object)
776 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) object;
778 avformat_free_context (ffmpegmux->context);
779 ffmpegmux->context = NULL;
781 gst_object_unref (ffmpegmux->collect);
783 if (G_OBJECT_CLASS (parent_class)->finalize)
784 G_OBJECT_CLASS (parent_class)->finalize (object);
788 gst_ffmpegmux_request_new_pad (GstElement * element,
789 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
791 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
792 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
793 GstFFMpegMuxPad *collect_pad;
797 enum AVMediaType type;
798 gint bitrate = 0, framesize = 0;
800 g_return_val_if_fail (templ != NULL, NULL);
801 g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
802 g_return_val_if_fail (ffmpegmux->opened == FALSE, NULL);
804 /* figure out a name that *we* like */
805 if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
806 padname = g_strdup_printf ("video_%u", ffmpegmux->videopads++);
807 type = AVMEDIA_TYPE_VIDEO;
810 } else if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
811 padname = g_strdup_printf ("audio_%u", ffmpegmux->audiopads++);
812 type = AVMEDIA_TYPE_AUDIO;
813 bitrate = 285 * 1024;
815 g_warning ("avmux: unknown pad template!");
820 pad = gst_pad_new_from_template (templ, padname);
821 collect_pad = (GstFFMpegMuxPad *)
822 gst_collect_pads_add_pad (ffmpegmux->collect, pad,
823 sizeof (GstFFMpegMuxPad), NULL, TRUE);
824 collect_pad->padnum = ffmpegmux->context->nb_streams;
826 /* small hack to put our own event pad function and chain up to collect pad */
827 ffmpegmux->event_function = GST_PAD_EVENTFUNC (pad);
828 gst_pad_set_event_function (pad,
829 GST_DEBUG_FUNCPTR (gst_ffmpegmux_sink_event));
831 gst_element_add_pad (element, pad);
833 /* AVStream needs to be created */
834 st = avformat_new_stream (ffmpegmux->context, NULL);
835 st->id = collect_pad->padnum;
836 st->codecpar->codec_type = type;
837 st->codecpar->codec_id = AV_CODEC_ID_NONE; /* this is a check afterwards */
838 st->codecpar->bit_rate = bitrate;
839 st->codecpar->frame_size = framesize;
840 /* we fill in codec during capsnego */
842 /* we love debug output (c) (tm) (r) */
843 GST_DEBUG ("Created %s pad for avmux_%s element",
844 padname, ((GstFFMpegMuxClass *) klass)->in_plugin->name);
851 gst_ffmpegmux_setcaps (GstPad * pad, GstObject * parent, GstCaps * caps)
853 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) parent;
854 GstFFMpegMuxPad *collect_pad;
858 collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
860 st = ffmpegmux->context->streams[collect_pad->padnum];
861 av_opt_set_int (ffmpegmux->context, "preload", ffmpegmux->preload, 0);
862 ffmpegmux->context->max_delay = ffmpegmux->max_delay;
863 memset (&tmp, 0, sizeof (tmp));
865 /* for the format-specific guesses, we'll go to
866 * our famous codec mapper */
867 if (gst_ffmpeg_caps_to_codecid (caps, &tmp) == AV_CODEC_ID_NONE)
870 avcodec_parameters_from_context (st->codecpar, &tmp);
872 /* copy over the aspect ratios, ffmpeg expects the stream aspect to match the
874 st->sample_aspect_ratio = st->codecpar->sample_aspect_ratio;
876 #ifdef TIZEN_FEATURE_LIBAV
877 /* ref counting bug fix */
878 gst_object_unref(ffmpegmux);
879 #endif /* TIZEN_FEATURE_LIBAV */
881 GST_LOG_OBJECT (pad, "accepted caps %" GST_PTR_FORMAT, caps);
887 #ifdef TIZEN_FEATURE_LIBAV
888 /* ref counting bug fix */
889 gst_object_unref (ffmpegmux);
890 #endif /* TIZEN_FEATURE_LIBAV */
891 GST_LOG_OBJECT (pad, "rejecting caps %" GST_PTR_FORMAT, caps);
898 gst_ffmpegmux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
900 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) parent;
903 switch (GST_EVENT_TYPE (event)) {
906 GstTagSetter *setter = GST_TAG_SETTER (ffmpegmux);
907 const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
909 gst_event_parse_tag (event, &taglist);
910 gst_tag_setter_merge_tags (setter, taglist, mode);
913 case GST_EVENT_CAPS:{
915 gst_event_parse_caps (event, &caps);
916 if (!(res = gst_ffmpegmux_setcaps (pad, parent, caps)))
924 /* chaining up to collectpads default event function */
925 res = ffmpegmux->event_function (pad, parent, event);
932 gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
934 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) user_data;
936 GstFFMpegMuxPad *best_pad;
937 GstClockTime best_time;
939 /* Re-enable once converted to new AVMetaData API
942 const GstTagList *tags;
945 /* open "file" (gstreamer protocol to next element) */
946 if (!ffmpegmux->opened) {
947 int open_flags = AVIO_FLAG_WRITE;
949 /* we do need all streams to have started capsnego,
950 * or things will go horribly wrong */
951 for (collected = ffmpegmux->collect->data; collected;
952 collected = g_slist_next (collected)) {
953 GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
954 AVStream *st = ffmpegmux->context->streams[collect_pad->padnum];
956 /* check whether the pad has successfully completed capsnego */
957 if (st->codecpar->codec_id == AV_CODEC_ID_NONE) {
958 GST_ELEMENT_ERROR (ffmpegmux, CORE, NEGOTIATION, (NULL),
959 ("no caps set on stream %d (%s)", collect_pad->padnum,
960 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ?
962 return GST_FLOW_ERROR;
964 /* set framerate for audio */
965 if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
966 switch (st->codecpar->codec_id) {
967 case AV_CODEC_ID_PCM_S16LE:
968 case AV_CODEC_ID_PCM_S16BE:
969 case AV_CODEC_ID_PCM_U16LE:
970 case AV_CODEC_ID_PCM_U16BE:
971 case AV_CODEC_ID_PCM_S8:
972 case AV_CODEC_ID_PCM_U8:
973 st->codecpar->frame_size = 1;
979 /* FIXME : This doesn't work for RAW AUDIO...
980 * in fact I'm wondering if it even works for any kind of audio... */
981 buffer = gst_collect_pads_peek (ffmpegmux->collect,
982 (GstCollectData *) collect_pad);
984 st->codecpar->frame_size =
985 st->codecpar->sample_rate *
986 GST_BUFFER_DURATION (buffer) / GST_SECOND;
987 gst_buffer_unref (buffer);
995 /* Re-enable once converted to new AVMetaData API
1000 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ffmpegmux));
1005 /* get the interesting ones */
1006 if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) {
1007 strncpy (ffmpegmux->context->title, s,
1008 sizeof (ffmpegmux->context->title));
1010 if (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)) {
1011 strncpy (ffmpegmux->context->author, s,
1012 sizeof (ffmpegmux->context->author));
1014 if (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &s)) {
1015 strncpy (ffmpegmux->context->copyright, s,
1016 sizeof (ffmpegmux->context->copyright));
1018 if (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &s)) {
1019 strncpy (ffmpegmux->context->comment, s,
1020 sizeof (ffmpegmux->context->comment));
1022 if (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)) {
1023 strncpy (ffmpegmux->context->album, s,
1024 sizeof (ffmpegmux->context->album));
1026 if (gst_tag_list_get_string (tags, GST_TAG_GENRE, &s)) {
1027 strncpy (ffmpegmux->context->genre, s,
1028 sizeof (ffmpegmux->context->genre));
1030 if (gst_tag_list_get_int (tags, GST_TAG_TRACK_NUMBER, &i)) {
1031 ffmpegmux->context->track = i;
1036 /* set the streamheader flag for gstffmpegprotocol if codec supports it */
1037 if (!strcmp (ffmpegmux->context->oformat->name, "flv")) {
1038 open_flags |= GST_FFMPEG_URL_STREAMHEADER;
1041 /* some house-keeping for downstream before starting data flow */
1042 /* stream-start (FIXME: create id based on input ids) */
1046 g_snprintf (s_id, sizeof (s_id), "avmux-%08x", g_random_int ());
1047 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_stream_start (s_id));
1053 /* let downstream know we think in BYTES and expect to do seeking later on */
1054 gst_segment_init (&segment, GST_FORMAT_BYTES);
1055 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_segment (&segment));
1058 if (gst_ffmpegdata_open (ffmpegmux->srcpad, open_flags,
1059 &ffmpegmux->context->pb) < 0) {
1060 GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
1061 ("Failed to open stream context in avmux"));
1062 return GST_FLOW_ERROR;
1065 /* now open the mux format */
1066 if (avformat_write_header (ffmpegmux->context, NULL) < 0) {
1067 GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL),
1068 ("Failed to write file header - check codec settings"));
1069 return GST_FLOW_ERROR;
1072 /* we're now opened */
1073 ffmpegmux->opened = TRUE;
1075 /* flush the header so it will be used as streamheader */
1076 avio_flush (ffmpegmux->context->pb);
1079 /* take the one with earliest timestamp,
1080 * and push it forward */
1082 best_time = GST_CLOCK_TIME_NONE;
1083 for (collected = ffmpegmux->collect->data; collected;
1084 collected = g_slist_next (collected)) {
1085 GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
1086 GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect,
1087 (GstCollectData *) collect_pad);
1089 /* if there's no buffer, just continue */
1090 if (buffer == NULL) {
1094 /* if we have no buffer yet, just use the first one */
1095 if (best_pad == NULL) {
1096 best_pad = collect_pad;
1097 best_time = GST_BUFFER_TIMESTAMP (buffer);
1101 /* if we do have one, only use this one if it's older */
1102 if (GST_BUFFER_TIMESTAMP (buffer) < best_time) {
1103 best_time = GST_BUFFER_TIMESTAMP (buffer);
1104 best_pad = collect_pad;
1108 gst_buffer_unref (buffer);
1110 /* Mux buffers with invalid timestamp first */
1111 if (!GST_CLOCK_TIME_IS_VALID (best_time))
1115 /* now handle the buffer, or signal EOS if we have
1116 * no buffers left */
1117 if (best_pad != NULL) {
1119 AVPacket pkt = { 0, };
1122 #ifdef TIZEN_FEATURE_LIBAV
1123 av_packet_unref(&pkt);
1125 #endif /* TIZEN_FEATURE_LIBAV */
1127 /* push out current buffer */
1129 gst_collect_pads_pop (ffmpegmux->collect, (GstCollectData *) best_pad);
1132 #ifdef TIZEN_FEATURE_LIBAV
1133 if (ffmpegmux->context->streams[best_pad->padnum]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
1134 pkt.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buf));
1136 #else /* TIZEN_FEATURE_LIBAV */
1137 pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
1138 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1139 #endif /* TIZEN_FEATURE_LIBAV */
1142 gst_buffer_map (buf, &map, GST_MAP_READ);
1143 pkt.data = map.data;
1144 pkt.size = map.size;
1146 pkt.stream_index = best_pad->padnum;
1148 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
1149 pkt.flags |= AV_PKT_FLAG_KEY;
1151 #ifdef TIZEN_FEATURE_LIBAV
1152 if (ffmpegmux->context->streams[best_pad->padnum]->codecpar->codec_type ==
1153 AVMEDIA_TYPE_VIDEO) {
1154 static int last_duration = -1;
1155 static int64_t last_dts = -1;
1156 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1157 pkt.duration = GST_TIME_AS_MSECONDS (GST_BUFFER_DURATION (buf));
1162 if (last_dts == -1) {
1164 ffmpegmux->context->streams[best_pad->padnum]->codecpar->stts_count++;
1166 /* check real duration : current dts - last dts */
1167 if (last_duration != (pkt.dts - last_dts)) {
1168 last_duration = pkt.dts - last_dts;
1169 ffmpegmux->context->streams[best_pad->padnum]->codecpar->stts_count++;
1173 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1174 ffmpegmux->context->streams[best_pad->padnum]->codecpar->i_frame_number++;
1177 static int last_duration_audio = -1;
1178 static int64_t last_dts_audio = -1;
1180 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1181 if (last_dts_audio == -1) {
1183 ffmpegmux->context->streams[best_pad->padnum]->codecpar->stts_count++;
1185 /* check real duration : current dts - last dts */
1186 if (last_duration_audio != (pkt.dts - last_dts_audio)) {
1187 last_duration_audio = pkt.dts - last_dts_audio;
1188 ffmpegmux->context->streams[best_pad->padnum]->codecpar->stts_count++;
1191 last_dts_audio = pkt.dts;
1194 gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1195 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1201 update_expected_trailer_size (ffmpegmux);
1202 #else /* TIZEN_FEATURE_LIBAV */
1203 if (GST_BUFFER_DURATION_IS_VALID (buf))
1205 gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1206 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1209 #endif /* TIZEN_FEATURE_LIBAV */
1210 av_write_frame (ffmpegmux->context, &pkt);
1211 gst_buffer_unmap (buf, &map);
1212 gst_buffer_unref (buf);
1215 av_write_trailer (ffmpegmux->context);
1216 ffmpegmux->opened = FALSE;
1217 avio_flush (ffmpegmux->context->pb);
1218 gst_ffmpegdata_close (ffmpegmux->context->pb);
1219 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ());
1220 return GST_FLOW_EOS;
1226 static GstStateChangeReturn
1227 gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
1229 GstStateChangeReturn ret;
1230 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (element);
1232 switch (transition) {
1233 case GST_STATE_CHANGE_NULL_TO_READY:
1235 case GST_STATE_CHANGE_READY_TO_PAUSED:
1236 gst_collect_pads_start (ffmpegmux->collect);
1238 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1240 case GST_STATE_CHANGE_PAUSED_TO_READY:
1241 gst_collect_pads_stop (ffmpegmux->collect);
1247 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1249 switch (transition) {
1250 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1252 case GST_STATE_CHANGE_PAUSED_TO_READY:
1253 #ifdef TIZEN_FEATURE_LIBAV
1256 FFStream *sti = NULL;
1257 #endif /* TIZEN_FEATURE_LIBAV */
1258 gst_tag_setter_reset_tags (GST_TAG_SETTER (ffmpegmux));
1259 if (ffmpegmux->opened) {
1260 ffmpegmux->opened = FALSE;
1261 gst_ffmpegdata_close (ffmpegmux->context->pb);
1263 #ifdef TIZEN_FEATURE_LIBAV
1264 for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
1265 sti = ffstream(ffmpegmux->context->streams[i]);
1266 ffmpegmux->context->streams[i]->start_time = AV_NOPTS_VALUE;
1267 ffmpegmux->context->streams[i]->duration = AV_NOPTS_VALUE;
1268 sti->cur_dts = AV_NOPTS_VALUE;
1273 case GST_STATE_CHANGE_READY_TO_NULL:
1283 gst_ffmpegmux_get_id_caps (enum AVCodecID *id_list)
1288 caps = gst_caps_new_empty ();
1289 for (i = 0; id_list[i] != AV_CODEC_ID_NONE; i++) {
1290 if ((t = gst_ffmpeg_codecid_to_caps (id_list[i], NULL, TRUE)))
1291 gst_caps_append (caps, t);
1293 if (gst_caps_is_empty (caps)) {
1294 gst_caps_unref (caps);
1301 /* set a list of integer values on the caps, e.g. for sample rates */
1303 gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps, const gchar * field,
1304 guint num, const gint * values)
1306 GValue list = { 0, };
1307 GValue val = { 0, };
1310 g_return_if_fail (GST_CAPS_IS_SIMPLE (caps));
1312 g_value_init (&list, GST_TYPE_LIST);
1313 g_value_init (&val, G_TYPE_INT);
1315 for (i = 0; i < num; ++i) {
1316 g_value_set_int (&val, values[i]);
1317 gst_value_list_append_value (&list, &val);
1320 gst_structure_set_value (gst_caps_get_structure (caps, 0), field, &list);
1322 g_value_unset (&val);
1323 g_value_unset (&list);
1327 gst_ffmpegmux_register (GstPlugin * plugin)
1329 GTypeInfo typeinfo = {
1330 sizeof (GstFFMpegMuxClass),
1331 (GBaseInitFunc) gst_ffmpegmux_base_init,
1333 (GClassInitFunc) gst_ffmpegmux_class_init,
1336 sizeof (GstFFMpegMux),
1338 (GInstanceInitFunc) gst_ffmpegmux_init,
1340 static const GInterfaceInfo tag_setter_info = {
1344 const AVOutputFormat *in_plugin;
1347 GST_LOG ("Registering muxers");
1349 while ((in_plugin = av_muxer_iterate (&i))) {
1351 GstRank rank = GST_RANK_MARGINAL;
1353 if ((!strncmp (in_plugin->name, "u16", 3)) ||
1354 (!strncmp (in_plugin->name, "s16", 3)) ||
1355 (!strncmp (in_plugin->name, "u24", 3)) ||
1356 (!strncmp (in_plugin->name, "s24", 3)) ||
1357 (!strncmp (in_plugin->name, "u8", 2)) ||
1358 (!strncmp (in_plugin->name, "s8", 2)) ||
1359 (!strncmp (in_plugin->name, "u32", 3)) ||
1360 (!strncmp (in_plugin->name, "s32", 3)) ||
1361 (!strncmp (in_plugin->name, "f32", 3)) ||
1362 (!strncmp (in_plugin->name, "f64", 3)) ||
1363 (!strncmp (in_plugin->name, "raw", 3)) ||
1364 (!strncmp (in_plugin->name, "crc", 3)) ||
1365 (!strncmp (in_plugin->name, "null", 4)) ||
1366 (!strncmp (in_plugin->name, "gif", 3)) ||
1367 (!strncmp (in_plugin->name, "fifo", 4)) ||
1368 (!strncmp (in_plugin->name, "frame", 5)) ||
1369 (!strncmp (in_plugin->name, "image", 5)) ||
1370 (!strncmp (in_plugin->name, "mulaw", 5)) ||
1371 (!strncmp (in_plugin->name, "alaw", 4)) ||
1372 (!strncmp (in_plugin->name, "h26", 3)) ||
1373 (!strncmp (in_plugin->name, "rtp", 3)) ||
1374 (!strncmp (in_plugin->name, "ass", 3)) ||
1375 (!strncmp (in_plugin->name, "ffmetadata", 10)) ||
1376 (!strncmp (in_plugin->name, "srt", 3)) ||
1377 (!strncmp (in_plugin->name, "scc", 3)) ||
1378 !strcmp (in_plugin->name, "ttml") ||
1379 !strcmp (in_plugin->name, "segment") ||
1380 !strcmp (in_plugin->name, "stream_segment,ssegment") ||
1381 !strcmp (in_plugin->name, "jacosub") ||
1382 !strcmp (in_plugin->name, "webvtt") ||
1383 !strcmp (in_plugin->name, "lrc") ||
1384 !strcmp (in_plugin->name, "microdvd") ||
1385 !strcmp (in_plugin->name, "tee") ||
1386 !strncmp (in_plugin->name, "webm", 4)
1388 GST_LOG ("Ignoring muxer %s", in_plugin->name);
1392 if (in_plugin->long_name != NULL) {
1393 if ((!strncmp (in_plugin->long_name, "raw ", 4))) {
1394 GST_LOG ("Ignoring raw muxer %s", in_plugin->name);
1399 if (gst_ffmpegmux_get_replacement (in_plugin->name))
1400 rank = GST_RANK_NONE;
1402 /* FIXME : We need a fast way to know whether we have mappings for this
1405 /* construct the type */
1406 type_name = g_strdup_printf ("avmux_%s", in_plugin->name);
1407 g_strdelimit (type_name, ".,|-<> ", '_');
1409 type = g_type_from_name (type_name);
1412 /* create the type now */
1413 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1414 g_type_set_qdata (type, GST_FFMUX_PARAMS_QDATA, (gpointer) in_plugin);
1415 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
1418 if (!gst_element_register (plugin, type_name, rank, type)) {
1426 GST_LOG ("Finished registering muxers");