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 #endif /* TIZEN_FEATURE_LIBAV */
40 typedef struct _GstFFMpegMux GstFFMpegMux;
41 typedef struct _GstFFMpegMuxPad GstFFMpegMuxPad;
43 struct _GstFFMpegMuxPad
45 GstCollectData collect; /* we extend the CollectData */
54 GstCollectPads *collect;
55 /* We need to keep track of our pads, so we do so here. */
58 AVFormatContext *context;
61 guint videopads, audiopads;
62 #ifdef TIZEN_FEATURE_LIBAV
63 guint expected_trailer_size;
64 guint nb_video_frames;
65 guint nb_audio_frames;
66 #endif /* TIZEN_FEATURE_LIBAV */
69 /* event_function is the collectpads default eventfunction */
70 GstPadEventFunction event_function;
75 typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;
77 struct _GstFFMpegMuxClass
79 GstElementClass parent_class;
81 AVOutputFormat *in_plugin;
84 #define GST_TYPE_FFMPEGMUX \
85 (gst_ffmpegdec_get_type())
86 #define GST_FFMPEGMUX(obj) \
87 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGMUX,GstFFMpegMux))
88 #define GST_FFMPEGMUX_CLASS(klass) \
89 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGMUX,GstFFMpegMuxClass))
90 #define GST_IS_FFMPEGMUX(obj) \
91 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGMUX))
92 #define GST_IS_FFMPEGMUX_CLASS(klass) \
93 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGMUX))
106 #ifdef TIZEN_FEATURE_LIBAV
107 , PROP_EXPECTED_TRAILER_SIZE,
108 PROP_NUMBER_VIDEO_FRAMES,
109 PROP_NUMBER_AUDIO_FRAMES
110 #endif /* TIZEN_FEATURE_LIBAV */
113 /* A number of function prototypes are given so we can refer to them later. */
114 static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass);
115 static void gst_ffmpegmux_base_init (gpointer g_class);
116 static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux,
117 GstFFMpegMuxClass * g_class);
118 static void gst_ffmpegmux_finalize (GObject * object);
120 static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps);
121 static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
122 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
123 static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads,
126 static gboolean gst_ffmpegmux_sink_event (GstPad * pad, GstObject * parent,
129 static GstStateChangeReturn gst_ffmpegmux_change_state (GstElement * element,
130 GstStateChange transition);
132 static void gst_ffmpegmux_set_property (GObject * object, guint prop_id,
133 const GValue * value, GParamSpec * pspec);
134 static void gst_ffmpegmux_get_property (GObject * object, guint prop_id,
135 GValue * value, GParamSpec * pspec);
137 static GstCaps *gst_ffmpegmux_get_id_caps (enum AVCodecID *id_list);
138 static void gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps,
139 const gchar * field, guint num, const gint * values);
141 #define GST_FFMUX_PARAMS_QDATA g_quark_from_static_string("avmux-params")
143 #ifdef TIZEN_FEATURE_LIBAV
144 static void gst_ffmpegmux_release_pad(GstElement *element, GstPad *pad);
145 #endif /* TIZEN_FEATURE_LIBAV */
147 static GstElementClass *parent_class = NULL;
149 /*static guint gst_ffmpegmux_signals[LAST_SIGNAL] = { 0 }; */
154 const char *replacement;
155 } GstFFMpegMuxReplacement;
158 gst_ffmpegmux_get_replacement (const char *name)
160 static const GstFFMpegMuxReplacement blacklist[] = {
162 {"matroska", "matroskamux"},
164 {"mpegts", "mpegtsmux"},
166 {"mpjpeg", "multipartmux"},
172 {"yuv4mpegpipe", "y4menc"},
174 {"adts", "aacparse"},
176 {"asf_stream", "asfmux"},
183 for (i = 0; i < sizeof (blacklist) / sizeof (blacklist[0]); i++) {
184 if (strcmp (blacklist[i].name, name) == 0) {
185 return blacklist[i].replacement;
193 gst_ffmpegmux_is_formatter (const char *name)
195 static const char *replace[] = {
200 for (i = 0; replace[i]; i++)
201 if (strcmp (replace[i], name) == 0)
206 #ifdef TIZEN_FEATURE_LIBAV
207 /* trailer entry size */
208 #define ENTRY_SIZE_VIDEO_STTS 8
209 #define ENTRY_SIZE_VIDEO_STSS 4
210 #define ENTRY_SIZE_VIDEO_STSZ 4
211 #define ENTRY_SIZE_VIDEO_STCO 4
212 #define ENTRY_SIZE_AUDIO_STTS 8
213 #define ENTRY_SIZE_AUDIO_STSZ 4
214 #define ENTRY_SIZE_AUDIO_STCO 4
216 #define ENTRY_SIZE_VIDEO_MPEG4_STSD 146
217 #define ENTRY_SIZE_VIDEO_H263P_STSD 102
218 #define ENTRY_SIZE_AUDIO_AAC_STSD 106
219 #define ENTRY_SIZE_AUDIO_AMR_STSD 69
221 #define ENTRY_SIZE_STSC 12
222 #define ENTRY_SIZE_VIDEO_ST 84 /*atom size (stss + stts + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
223 #define ENTRY_SIZE_AUDIO_ST 68 /*atom size (stss + stsc + stsz + stco ) * (size + atom + version + flags + sample count)+stsz(sample size) */
226 #define MUX_ADTS_NAME "adts"
227 #define MUX_AMR_NAME "amr"
228 #define MUX_MP4_NAME "mp4"
229 #define MUX_ADTS_SIZE_HEADER 8
230 #define MUX_ADTS_SIZE_ENTRY 7
231 #define MUX_AMR_SIZE_HEADER 6
234 #define MUX_COMMON_SIZE_3GP_HEADER 290 /* ftyp + free + moov + mvhd + +iods + udta */
235 #define MUX_COMMON_SIZE_MP4_HEADER 378 /* ftyp + free + moov + mvhd + +iods + udta (meta) */
236 #define MUX_COMMON_SIZE_MP4_VIDEO_HEADER 305
237 #define MUX_COMMON_SIZE_MP4_AUDIO_HEADER 253
239 #define MUX_INFO_SIZE_LOCATION 106 /* loci + .xyz */
242 update_expected_trailer_size (GstFFMpegMux * ffmpegmux)
245 guint nb_video_frames = 0;
246 guint nb_video_i_frames = 0;
247 guint nb_video_stts_entry = 0;
248 guint nb_audio_frames = 0;
249 guint nb_audio_stts_entry = 0;
250 gboolean video_stream = FALSE;
251 gboolean audio_stream = FALSE;
253 AVCodecContext *codec_context = NULL;
254 enum AVCodecID video_codec_id;
255 enum AVCodecID audio_codec_id;
257 if (ffmpegmux == NULL) {
258 GST_WARNING ("ffmpegmux is NULL");
262 for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
263 codec_context = ffmpegmux->context->streams[i]->codec;
264 if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO) {
265 nb_video_frames += codec_context->frame_number;
266 nb_video_i_frames += codec_context->i_frame_number;
267 nb_video_stts_entry += codec_context->stts_count;
270 video_codec_id = codec_context->codec_id;
271 } else if (codec_context->codec_type == AVMEDIA_TYPE_AUDIO) {
272 nb_audio_frames += codec_context->frame_number;
273 nb_audio_stts_entry += codec_context->stts_count;
276 audio_codec_id = codec_context->codec_id;
283 ftyp = 28 (MPEG4 ftype: 28 , H263P fype: 28)
289 udta = 114(meta in case of audio only) or
290 114(loci in case of video only or video/audio) or
291 202( with meta in MP4)
292 96 ( audio only with meta )
294 total : 290 (3GP) or 378 (MP4)
299 edts = 48 ( addition )
305 dinf = 36 ( 8 , dref : 16 , url : 12 )
306 stbl = 8 ( common video total : 305 )
307 stsd = 146 ( addtion : 16 + , mp4v: 86 ,esds : 44 )
308 stts = 16 + (8*stts_count)
309 stss = 16 + (4*I-frame)
311 stsz = 20 + (4*frame)
312 stco = 16 + (4*frame)
314 - VIDEO:H.264 = 487(or 489) + (8*stts_count) + (8*frame) + (4*I-frame)
317 edts = 48 ( addition )
323 dinf = 36 ( 8 , dref : 16 , url : 12 )
325 stsd = 134 (SPS 9, PPS 4) or 136 (SPS 111, PPS 4)
326 stts = 16 + (8*stts_count)
327 stss = 16 + (4*I-frame)
329 stsz = 20 + (4*frame)
330 stco = 16 + (4*frame)
332 - VIDEO:H.263 = 470 + + (8*stts_count) + (8*frame) + (4*I-frame)
335 edts = 48 ( addition )
343 stsd = 102 -> different from H.264
344 stts = 16 + (8*stts_count)
345 stss = 16 + (4*I-frame)
347 stsz = 20 + (4*frame)
348 stco = 16 + (4*frame)
350 - AUDIO:AAC = 424 + + (8*stts_count) + (8*audio_frame)
358 dinf = 36 ( 8 , dref : 16 , url : 12 )
359 stbl = 8 ( common video total : 253 )
360 stsd = 106 + ( addtion : 16 , mp4v: 46 ,esds : 54 )
361 stts = 16 + (8*stts_count)
363 stsz = 20 + (4*frame)
364 stco = 16 + (4*frame)
366 - AUDIO:AMR = 410 + (4*audio_frame)
376 stsd = 69 -> different from AAC
377 stts = 24 -> different from AAC
379 stsz = 20 -> different from AAC
380 stco = 16 + (4*frame)
383 /* Calculate trailer size for video stream */
384 if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
386 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
388 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_MP4_NAME)) {
389 exp_size = MUX_COMMON_SIZE_MP4_HEADER;
391 exp_size = MUX_COMMON_SIZE_3GP_HEADER;
393 //GST_INFO_OBJECT(ffmpegmux, "size: common size=[%d]", exp_size);
396 /* ftyp + free + moov + mvhd + udta : H.264 -> 240, H.263 -> 236 */
397 /* trak size except frame related : H.264 -> 489, H.263 -> 470 */
398 if (video_codec_id == AV_CODEC_ID_H263
399 || video_codec_id == AV_CODEC_ID_H263P) {
401 MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_H263P_STSD;
402 } else if (video_codec_id == AV_CODEC_ID_MPEG4) {
404 MUX_COMMON_SIZE_MP4_VIDEO_HEADER + ENTRY_SIZE_VIDEO_MPEG4_STSD;
406 exp_size += 240 + 489;
409 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
413 ENTRY_SIZE_VIDEO_ST + (ENTRY_SIZE_VIDEO_STTS * nb_video_stts_entry) +
414 (ENTRY_SIZE_VIDEO_STSS * nb_video_i_frames) + (ENTRY_SIZE_STSC) +
415 ((ENTRY_SIZE_VIDEO_STSZ + ENTRY_SIZE_VIDEO_STCO) * nb_video_frames);
417 //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);
420 /* Calculate trailer size for audio stream */
421 if (!strcmp (ffmpegmux->context->oformat->name, MUX_ADTS_NAME)) {
424 MUX_ADTS_SIZE_HEADER + (MUX_ADTS_SIZE_ENTRY * nb_audio_frames);
425 } else if (!strcmp (ffmpegmux->context->oformat->name, MUX_AMR_NAME)) {
426 /* only audio avmux_amr */
427 exp_size = MUX_AMR_SIZE_HEADER;
429 /* avmux_3gp , avmux_mp4 */
431 /* audio only does not contain location info now */
432 exp_size -= MUX_INFO_SIZE_LOCATION;
434 /* others - avmux_3gp/mp4/amr */
435 if (audio_codec_id == AV_CODEC_ID_AMR_NB) {
438 MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AMR_STSD;
440 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
443 ENTRY_SIZE_AUDIO_ST +
444 (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
445 (ENTRY_SIZE_AUDIO_STCO * nb_audio_frames);
449 MUX_COMMON_SIZE_MP4_AUDIO_HEADER + ENTRY_SIZE_AUDIO_AAC_STSD;
451 //GST_INFO_OBJECT(ffmpegmux, "size: [%d]",exp_size);
454 ENTRY_SIZE_AUDIO_ST +
455 (ENTRY_SIZE_AUDIO_STTS * nb_audio_stts_entry) + (ENTRY_SIZE_STSC) +
456 ((ENTRY_SIZE_AUDIO_STSZ + ENTRY_SIZE_AUDIO_STCO) * nb_audio_frames);
461 //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);
463 ffmpegmux->expected_trailer_size = exp_size;
464 ffmpegmux->nb_video_frames = nb_video_frames;
465 ffmpegmux->nb_audio_frames = nb_audio_frames;
469 #endif /* TIZEN_FEATURE_LIBAV */
472 gst_ffmpegmux_base_init (gpointer g_class)
474 GstFFMpegMuxClass *klass = (GstFFMpegMuxClass *) g_class;
475 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
476 GstPadTemplate *videosinktempl, *audiosinktempl, *srctempl;
477 AVOutputFormat *in_plugin;
478 GstCaps *srccaps, *audiosinkcaps, *videosinkcaps;
479 enum AVCodecID *video_ids = NULL, *audio_ids = NULL;
480 gchar *longname, *description, *name;
481 const char *replacement;
482 gboolean is_formatter;
485 (AVOutputFormat *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
486 GST_FFMUX_PARAMS_QDATA);
487 g_assert (in_plugin != NULL);
489 name = g_strdup (in_plugin->name);
490 g_strdelimit (name, ".,|-<> ", '_');
492 /* construct the element details struct */
493 replacement = gst_ffmpegmux_get_replacement (in_plugin->name);
494 is_formatter = gst_ffmpegmux_is_formatter (in_plugin->name);
495 if (replacement != NULL) {
497 g_strdup_printf ("libav %s %s (not recommended, use %s instead)",
498 in_plugin->long_name, is_formatter ? "formatter" : "muxer",
501 g_strdup_printf ("libav %s %s (not recommended, use %s instead)",
502 in_plugin->long_name, is_formatter ? "formatter" : "muxer",
505 longname = g_strdup_printf ("libav %s %s", in_plugin->long_name,
506 is_formatter ? "formatter" : "muxer");
507 description = g_strdup_printf ("libav %s %s", in_plugin->long_name,
508 is_formatter ? "formatter" : "muxer");
510 gst_element_class_set_metadata (element_class, longname,
511 is_formatter ? "Formatter/Metadata" : "Codec/Muxer", description,
512 "Wim Taymans <wim.taymans@chello.be>, "
513 "Ronald Bultje <rbultje@ronald.bitfreak.net>");
515 g_free (description);
517 /* Try to find the caps that belongs here */
518 srccaps = gst_ffmpeg_formatid_to_caps (name);
520 GST_DEBUG ("Couldn't get source caps for muxer '%s', skipping", name);
524 if (!gst_ffmpeg_formatid_get_codecids (in_plugin->name,
525 &video_ids, &audio_ids, in_plugin)) {
526 gst_caps_unref (srccaps);
527 GST_DEBUG ("Couldn't get sink caps for muxer '%s'. Most likely because "
528 "no input format mapping exists.", name);
532 videosinkcaps = video_ids ? gst_ffmpegmux_get_id_caps (video_ids) : NULL;
533 audiosinkcaps = audio_ids ? gst_ffmpegmux_get_id_caps (audio_ids) : NULL;
535 /* fix up allowed caps for some muxers */
536 /* FIXME : This should be in gstffmpegcodecmap.c ! */
537 if (strcmp (in_plugin->name, "flv") == 0) {
538 const gint rates[] = { 44100, 22050, 11025 };
540 gst_ffmpeg_mux_simple_caps_set_int_list (audiosinkcaps, "rate", 3, rates);
541 } else if (strcmp (in_plugin->name, "dv") == 0) {
542 gst_caps_set_simple (audiosinkcaps,
543 "rate", G_TYPE_INT, 48000, "channels", G_TYPE_INT, 2, NULL);
548 srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps);
549 gst_element_class_add_pad_template (element_class, srctempl);
550 gst_caps_unref (srccaps);
553 audiosinktempl = gst_pad_template_new ("audio_%u",
554 GST_PAD_SINK, GST_PAD_REQUEST, audiosinkcaps);
555 gst_element_class_add_pad_template (element_class, audiosinktempl);
556 gst_caps_unref (audiosinkcaps);
560 videosinktempl = gst_pad_template_new ("video_%u",
561 GST_PAD_SINK, GST_PAD_REQUEST, videosinkcaps);
562 gst_element_class_add_pad_template (element_class, videosinktempl);
563 gst_caps_unref (videosinkcaps);
567 klass->in_plugin = in_plugin;
573 gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
575 GObjectClass *gobject_class;
576 GstElementClass *gstelement_class;
577 #ifdef TIZEN_FEATURE_LIBAV
578 GParamSpec * tspec = NULL;
579 #endif /* TIZEN_FEATURE_LIBAV */
581 gobject_class = (GObjectClass *) klass;
582 gstelement_class = (GstElementClass *) klass;
584 parent_class = g_type_class_peek_parent (klass);
586 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_set_property);
587 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ffmpegmux_get_property);
589 g_object_class_install_property (gobject_class, PROP_PRELOAD,
590 g_param_spec_int ("preload", "preload",
591 "Set the initial demux-decode delay (in microseconds)",
592 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
594 g_object_class_install_property (gobject_class, PROP_MAXDELAY,
595 g_param_spec_int ("maxdelay", "maxdelay",
596 "Set the maximum demux-decode delay (in microseconds)", 0, G_MAXINT,
597 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
599 gstelement_class->request_new_pad = gst_ffmpegmux_request_new_pad;
600 gstelement_class->change_state = gst_ffmpegmux_change_state;
601 gobject_class->finalize = gst_ffmpegmux_finalize;
603 #ifdef TIZEN_FEATURE_LIBAV
604 gstelement_class->release_pad = gst_ffmpegmux_release_pad;
607 tspec = g_param_spec_uint("expected-trailer-size", "Expected Trailer Size",
608 "Expected trailer size (bytes)",
609 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
611 g_object_class_install_property(gobject_class, PROP_EXPECTED_TRAILER_SIZE, tspec);
613 GST_ERROR("g_param_spec failed for \"expected-trailer-size\"");
615 tspec = g_param_spec_uint("number-video-frames", "Number of video frames",
616 "Current number of video frames",
617 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
619 g_object_class_install_property (gobject_class, PROP_NUMBER_VIDEO_FRAMES, tspec);
621 GST_ERROR("g_param_spec failed for \"number-video-frames\"");
623 tspec = g_param_spec_uint("number-audio-frames", "Number of audio frames",
624 "Current number of audio frames",
625 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
627 g_object_class_install_property (gobject_class, PROP_NUMBER_AUDIO_FRAMES, tspec);
629 GST_ERROR("g_param_spec failed for \"number-audio-frames\"");
630 #endif /* TIZEN_FEATURE_LIBAV */
634 gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux, GstFFMpegMuxClass * g_class)
636 GstElementClass *klass = GST_ELEMENT_CLASS (g_class);
637 GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass *) klass;
638 GstPadTemplate *templ = gst_element_class_get_pad_template (klass, "src");
640 ffmpegmux->srcpad = gst_pad_new_from_template (templ, "src");
641 gst_pad_set_caps (ffmpegmux->srcpad, gst_pad_template_get_caps (templ));
642 gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->srcpad);
644 ffmpegmux->collect = gst_collect_pads_new ();
645 gst_collect_pads_set_function (ffmpegmux->collect,
646 (GstCollectPadsFunction) gst_ffmpegmux_collected, ffmpegmux);
648 ffmpegmux->context = avformat_alloc_context ();
649 ffmpegmux->context->oformat = oclass->in_plugin;
650 ffmpegmux->context->nb_streams = 0;
651 ffmpegmux->opened = FALSE;
653 ffmpegmux->videopads = 0;
654 ffmpegmux->audiopads = 0;
655 ffmpegmux->max_delay = 0;
657 #ifdef TIZEN_FEATURE_LIBAV
658 ffmpegmux->expected_trailer_size = 0;
659 ffmpegmux->nb_video_frames = 0;
660 ffmpegmux->nb_audio_frames = 0;
661 #endif /* TIZEN_FEATURE_LIBAV */
664 #ifdef TIZEN_FEATURE_LIBAV
666 gst_ffmpegmux_release_pad (GstElement * element, GstPad * pad)
668 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
669 GstFFMpegMuxPad *collect_pad;
672 collect_pad = (GstFFMpegMuxPad *)gst_pad_get_element_private(pad);
674 GST_DEBUG ("Release requested pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
675 st = ffmpegmux->context->streams[collect_pad->padnum];
678 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
679 ffmpegmux->videopads--;
681 ffmpegmux->audiopads--;
683 if (st->codec->extradata) {
684 av_free(st->codec->extradata);
685 st->codec->extradata = NULL;
690 if (ffmpegmux->context->priv_data) {
691 MOVMuxContext *mov = ffmpegmux->context->priv_data;
692 if (mov && mov->tracks) {
693 for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
694 MOVTrack *trk = &mov->tracks[i];
695 if (trk && trk->vos_data) {
696 av_free(trk->vos_data);
697 trk->vos_data = NULL;
700 av_free(mov->tracks);
703 av_free(ffmpegmux->context->priv_data);
704 ffmpegmux->context->priv_data = NULL;
706 ffmpegmux->context->nb_streams--;
710 gst_collect_pads_remove_pad(ffmpegmux->collect, pad);
711 gst_element_remove_pad(element, pad);
713 #endif /* TIZEN_FEATURE_LIBAV */
716 gst_ffmpegmux_set_property (GObject * object, guint prop_id,
717 const GValue * value, GParamSpec * pspec)
721 src = (GstFFMpegMux *) object;
725 src->preload = g_value_get_int (value);
728 src->max_delay = g_value_get_int (value);
731 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
737 gst_ffmpegmux_get_property (GObject * object, guint prop_id, GValue * value,
742 src = (GstFFMpegMux *) object;
746 g_value_set_int (value, src->preload);
749 g_value_set_int (value, src->max_delay);
751 #ifdef TIZEN_FEATURE_LIBAV
752 case PROP_EXPECTED_TRAILER_SIZE:
753 g_value_set_uint(value, src->expected_trailer_size);
755 case PROP_NUMBER_VIDEO_FRAMES:
756 g_value_set_uint(value, src->nb_video_frames);
758 case PROP_NUMBER_AUDIO_FRAMES:
759 g_value_set_uint(value, src->nb_audio_frames);
761 #endif /* TIZEN_FEATURE_LIBAV */
763 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
770 gst_ffmpegmux_finalize (GObject * object)
772 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) object;
774 avformat_free_context (ffmpegmux->context);
775 ffmpegmux->context = NULL;
777 gst_object_unref (ffmpegmux->collect);
779 if (G_OBJECT_CLASS (parent_class)->finalize)
780 G_OBJECT_CLASS (parent_class)->finalize (object);
784 gst_ffmpegmux_request_new_pad (GstElement * element,
785 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
787 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
788 GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
789 GstFFMpegMuxPad *collect_pad;
793 enum AVMediaType type;
794 gint bitrate = 0, framesize = 0;
796 g_return_val_if_fail (templ != NULL, NULL);
797 g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
798 g_return_val_if_fail (ffmpegmux->opened == FALSE, NULL);
800 /* figure out a name that *we* like */
801 if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
802 padname = g_strdup_printf ("video_%u", ffmpegmux->videopads++);
803 type = AVMEDIA_TYPE_VIDEO;
806 } else if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
807 padname = g_strdup_printf ("audio_%u", ffmpegmux->audiopads++);
808 type = AVMEDIA_TYPE_AUDIO;
809 bitrate = 285 * 1024;
811 g_warning ("avmux: unknown pad template!");
816 pad = gst_pad_new_from_template (templ, padname);
817 collect_pad = (GstFFMpegMuxPad *)
818 gst_collect_pads_add_pad (ffmpegmux->collect, pad,
819 sizeof (GstFFMpegMuxPad), NULL, TRUE);
820 collect_pad->padnum = ffmpegmux->context->nb_streams;
822 /* small hack to put our own event pad function and chain up to collect pad */
823 ffmpegmux->event_function = GST_PAD_EVENTFUNC (pad);
824 gst_pad_set_event_function (pad,
825 GST_DEBUG_FUNCPTR (gst_ffmpegmux_sink_event));
827 gst_element_add_pad (element, pad);
829 /* AVStream needs to be created */
830 st = avformat_new_stream (ffmpegmux->context, NULL);
831 st->id = collect_pad->padnum;
832 st->codecpar->codec_type = type;
833 st->codecpar->codec_id = AV_CODEC_ID_NONE; /* this is a check afterwards */
834 st->codecpar->bit_rate = bitrate;
835 st->codecpar->frame_size = framesize;
836 /* we fill in codec during capsnego */
838 /* we love debug output (c) (tm) (r) */
839 GST_DEBUG ("Created %s pad for avmux_%s element",
840 padname, ((GstFFMpegMuxClass *) klass)->in_plugin->name);
847 * gst_ffmpegmux_setcaps
853 * Returns: #TRUE on success.
856 gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps)
858 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (gst_pad_get_parent (pad));
859 GstFFMpegMuxPad *collect_pad;
863 collect_pad = (GstFFMpegMuxPad *) gst_pad_get_element_private (pad);
865 st = ffmpegmux->context->streams[collect_pad->padnum];
866 av_opt_set_int (ffmpegmux->context, "preload", ffmpegmux->preload, 0);
867 ffmpegmux->context->max_delay = ffmpegmux->max_delay;
868 memset (&tmp, 0, sizeof (tmp));
870 /* for the format-specific guesses, we'll go to
871 * our famous codec mapper */
872 if (gst_ffmpeg_caps_to_codecid (caps, &tmp) == AV_CODEC_ID_NONE)
875 avcodec_parameters_from_context (st->codecpar, &tmp);
877 /* copy over the aspect ratios, ffmpeg expects the stream aspect to match the
879 st->sample_aspect_ratio = st->codecpar->sample_aspect_ratio;
881 #ifdef TIZEN_FEATURE_LIBAV
882 /* ref counting bug fix */
883 gst_object_unref(ffmpegmux);
884 #endif /* TIZEN_FEATURE_LIBAV */
886 GST_LOG_OBJECT (pad, "accepted caps %" GST_PTR_FORMAT, caps);
892 #ifdef TIZEN_FEATURE_LIBAV
893 /* ref counting bug fix */
894 gst_object_unref (ffmpegmux);
895 #endif /* TIZEN_FEATURE_LIBAV */
896 GST_LOG_OBJECT (pad, "rejecting caps %" GST_PTR_FORMAT, caps);
903 gst_ffmpegmux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
905 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) parent;
908 switch (GST_EVENT_TYPE (event)) {
911 GstTagSetter *setter = GST_TAG_SETTER (ffmpegmux);
912 const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
914 gst_event_parse_tag (event, &taglist);
915 gst_tag_setter_merge_tags (setter, taglist, mode);
918 case GST_EVENT_CAPS:{
920 gst_event_parse_caps (event, &caps);
921 if (!(res = gst_ffmpegmux_setcaps (pad, caps)))
929 /* chaining up to collectpads default event function */
930 res = ffmpegmux->event_function (pad, parent, event);
937 gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
939 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) user_data;
941 GstFFMpegMuxPad *best_pad;
942 GstClockTime best_time;
944 /* Re-enable once converted to new AVMetaData API
947 const GstTagList *tags;
950 /* open "file" (gstreamer protocol to next element) */
951 if (!ffmpegmux->opened) {
952 int open_flags = AVIO_FLAG_WRITE;
954 /* we do need all streams to have started capsnego,
955 * or things will go horribly wrong */
956 for (collected = ffmpegmux->collect->data; collected;
957 collected = g_slist_next (collected)) {
958 GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
959 AVStream *st = ffmpegmux->context->streams[collect_pad->padnum];
961 /* check whether the pad has successfully completed capsnego */
962 if (st->codecpar->codec_id == AV_CODEC_ID_NONE) {
963 GST_ELEMENT_ERROR (ffmpegmux, CORE, NEGOTIATION, (NULL),
964 ("no caps set on stream %d (%s)", collect_pad->padnum,
965 (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ?
967 return GST_FLOW_ERROR;
969 /* set framerate for audio */
970 if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
971 switch (st->codecpar->codec_id) {
972 case AV_CODEC_ID_PCM_S16LE:
973 case AV_CODEC_ID_PCM_S16BE:
974 case AV_CODEC_ID_PCM_U16LE:
975 case AV_CODEC_ID_PCM_U16BE:
976 case AV_CODEC_ID_PCM_S8:
977 case AV_CODEC_ID_PCM_U8:
978 st->codecpar->frame_size = 1;
984 /* FIXME : This doesn't work for RAW AUDIO...
985 * in fact I'm wondering if it even works for any kind of audio... */
986 buffer = gst_collect_pads_peek (ffmpegmux->collect,
987 (GstCollectData *) collect_pad);
989 st->codecpar->frame_size =
990 st->codecpar->sample_rate *
991 GST_BUFFER_DURATION (buffer) / GST_SECOND;
992 gst_buffer_unref (buffer);
1000 /* Re-enable once converted to new AVMetaData API
1005 tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ffmpegmux));
1010 /* get the interesting ones */
1011 if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) {
1012 strncpy (ffmpegmux->context->title, s,
1013 sizeof (ffmpegmux->context->title));
1015 if (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)) {
1016 strncpy (ffmpegmux->context->author, s,
1017 sizeof (ffmpegmux->context->author));
1019 if (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &s)) {
1020 strncpy (ffmpegmux->context->copyright, s,
1021 sizeof (ffmpegmux->context->copyright));
1023 if (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &s)) {
1024 strncpy (ffmpegmux->context->comment, s,
1025 sizeof (ffmpegmux->context->comment));
1027 if (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)) {
1028 strncpy (ffmpegmux->context->album, s,
1029 sizeof (ffmpegmux->context->album));
1031 if (gst_tag_list_get_string (tags, GST_TAG_GENRE, &s)) {
1032 strncpy (ffmpegmux->context->genre, s,
1033 sizeof (ffmpegmux->context->genre));
1035 if (gst_tag_list_get_int (tags, GST_TAG_TRACK_NUMBER, &i)) {
1036 ffmpegmux->context->track = i;
1041 /* set the streamheader flag for gstffmpegprotocol if codec supports it */
1042 if (!strcmp (ffmpegmux->context->oformat->name, "flv")) {
1043 open_flags |= GST_FFMPEG_URL_STREAMHEADER;
1046 /* some house-keeping for downstream before starting data flow */
1047 /* stream-start (FIXME: create id based on input ids) */
1051 g_snprintf (s_id, sizeof (s_id), "avmux-%08x", g_random_int ());
1052 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_stream_start (s_id));
1058 /* let downstream know we think in BYTES and expect to do seeking later on */
1059 gst_segment_init (&segment, GST_FORMAT_BYTES);
1060 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_segment (&segment));
1063 if (gst_ffmpegdata_open (ffmpegmux->srcpad, open_flags,
1064 &ffmpegmux->context->pb) < 0) {
1065 GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL),
1066 ("Failed to open stream context in avmux"));
1067 return GST_FLOW_ERROR;
1070 /* now open the mux format */
1071 if (avformat_write_header (ffmpegmux->context, NULL) < 0) {
1072 GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL),
1073 ("Failed to write file header - check codec settings"));
1074 return GST_FLOW_ERROR;
1077 /* we're now opened */
1078 ffmpegmux->opened = TRUE;
1080 /* flush the header so it will be used as streamheader */
1081 avio_flush (ffmpegmux->context->pb);
1084 /* take the one with earliest timestamp,
1085 * and push it forward */
1087 best_time = GST_CLOCK_TIME_NONE;
1088 for (collected = ffmpegmux->collect->data; collected;
1089 collected = g_slist_next (collected)) {
1090 GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
1091 GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect,
1092 (GstCollectData *) collect_pad);
1094 /* if there's no buffer, just continue */
1095 if (buffer == NULL) {
1099 /* if we have no buffer yet, just use the first one */
1100 if (best_pad == NULL) {
1101 best_pad = collect_pad;
1102 best_time = GST_BUFFER_TIMESTAMP (buffer);
1106 /* if we do have one, only use this one if it's older */
1107 if (GST_BUFFER_TIMESTAMP (buffer) < best_time) {
1108 best_time = GST_BUFFER_TIMESTAMP (buffer);
1109 best_pad = collect_pad;
1113 gst_buffer_unref (buffer);
1115 /* Mux buffers with invalid timestamp first */
1116 if (!GST_CLOCK_TIME_IS_VALID (best_time))
1120 /* now handle the buffer, or signal EOS if we have
1121 * no buffers left */
1122 if (best_pad != NULL) {
1124 AVPacket pkt = { 0, };
1127 #ifdef TIZEN_FEATURE_LIBAV
1128 av_init_packet (&pkt);
1130 #endif /* TIZEN_FEATURE_LIBAV */
1132 /* push out current buffer */
1134 gst_collect_pads_pop (ffmpegmux->collect, (GstCollectData *) best_pad);
1137 #ifdef TIZEN_FEATURE_LIBAV
1138 if (ffmpegmux->context->streams[best_pad->padnum]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1139 pkt.pts = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buf));
1141 #else /* TIZEN_FEATURE_LIBAV */
1142 pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf),
1143 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1144 #endif /* TIZEN_FEATURE_LIBAV */
1147 gst_buffer_map (buf, &map, GST_MAP_READ);
1148 pkt.data = map.data;
1149 pkt.size = map.size;
1151 pkt.stream_index = best_pad->padnum;
1153 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
1154 pkt.flags |= AV_PKT_FLAG_KEY;
1156 #ifdef TIZEN_FEATURE_LIBAV
1157 if (ffmpegmux->context->streams[best_pad->padnum]->codec->codec_type ==
1158 AVMEDIA_TYPE_VIDEO) {
1159 static int last_duration = -1;
1160 static int64_t last_dts = -1;
1161 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1162 pkt.duration = GST_TIME_AS_MSECONDS (GST_BUFFER_DURATION (buf));
1167 if (last_dts == -1) {
1169 ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1171 /* check real duration : current dts - last dts */
1172 if (last_duration != (pkt.dts - last_dts)) {
1173 last_duration = pkt.dts - last_dts;
1174 ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1178 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1179 ffmpegmux->context->streams[best_pad->padnum]->codec->i_frame_number++;
1182 static int last_duration_audio = -1;
1183 static int64_t last_dts_audio = -1;
1185 if (GST_BUFFER_DURATION_IS_VALID (buf)) {
1186 if (last_dts_audio == -1) {
1188 ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1190 /* check real duration : current dts - last dts */
1191 if (last_duration_audio != (pkt.dts - last_dts_audio)) {
1192 last_duration_audio = pkt.dts - last_dts_audio;
1193 ffmpegmux->context->streams[best_pad->padnum]->codec->stts_count++;
1196 last_dts_audio = pkt.dts;
1199 gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1200 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1206 update_expected_trailer_size (ffmpegmux);
1207 #else /* TIZEN_FEATURE_LIBAV */
1208 if (GST_BUFFER_DURATION_IS_VALID (buf))
1210 gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf),
1211 ffmpegmux->context->streams[best_pad->padnum]->time_base);
1214 #endif /* TIZEN_FEATURE_LIBAV */
1215 av_write_frame (ffmpegmux->context, &pkt);
1216 gst_buffer_unmap (buf, &map);
1217 gst_buffer_unref (buf);
1220 av_write_trailer (ffmpegmux->context);
1221 ffmpegmux->opened = FALSE;
1222 avio_flush (ffmpegmux->context->pb);
1223 gst_ffmpegdata_close (ffmpegmux->context->pb);
1224 gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ());
1225 return GST_FLOW_EOS;
1231 static GstStateChangeReturn
1232 gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
1234 GstStateChangeReturn ret;
1235 GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (element);
1237 switch (transition) {
1238 case GST_STATE_CHANGE_NULL_TO_READY:
1240 case GST_STATE_CHANGE_READY_TO_PAUSED:
1241 gst_collect_pads_start (ffmpegmux->collect);
1243 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1245 case GST_STATE_CHANGE_PAUSED_TO_READY:
1246 gst_collect_pads_stop (ffmpegmux->collect);
1252 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1254 switch (transition) {
1255 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1257 case GST_STATE_CHANGE_PAUSED_TO_READY:
1258 #ifdef TIZEN_FEATURE_LIBAV
1261 #endif /* TIZEN_FEATURE_LIBAV */
1262 gst_tag_setter_reset_tags (GST_TAG_SETTER (ffmpegmux));
1263 if (ffmpegmux->opened) {
1264 ffmpegmux->opened = FALSE;
1265 gst_ffmpegdata_close (ffmpegmux->context->pb);
1267 #ifdef TIZEN_FEATURE_LIBAV
1268 for (i = 0 ; i < ffmpegmux->context->nb_streams ; i++) {
1269 ffmpegmux->context->streams[i]->start_time = AV_NOPTS_VALUE;
1270 ffmpegmux->context->streams[i]->duration = AV_NOPTS_VALUE;
1271 ffmpegmux->context->streams[i]->cur_dts = AV_NOPTS_VALUE;
1276 case GST_STATE_CHANGE_READY_TO_NULL:
1286 gst_ffmpegmux_get_id_caps (enum AVCodecID *id_list)
1291 caps = gst_caps_new_empty ();
1292 for (i = 0; id_list[i] != AV_CODEC_ID_NONE; i++) {
1293 if ((t = gst_ffmpeg_codecid_to_caps (id_list[i], NULL, TRUE)))
1294 gst_caps_append (caps, t);
1296 if (gst_caps_is_empty (caps)) {
1297 gst_caps_unref (caps);
1304 /* set a list of integer values on the caps, e.g. for sample rates */
1306 gst_ffmpeg_mux_simple_caps_set_int_list (GstCaps * caps, const gchar * field,
1307 guint num, const gint * values)
1309 GValue list = { 0, };
1310 GValue val = { 0, };
1313 g_return_if_fail (GST_CAPS_IS_SIMPLE (caps));
1315 g_value_init (&list, GST_TYPE_LIST);
1316 g_value_init (&val, G_TYPE_INT);
1318 for (i = 0; i < num; ++i) {
1319 g_value_set_int (&val, values[i]);
1320 gst_value_list_append_value (&list, &val);
1323 gst_structure_set_value (gst_caps_get_structure (caps, 0), field, &list);
1325 g_value_unset (&val);
1326 g_value_unset (&list);
1330 gst_ffmpegmux_register (GstPlugin * plugin)
1332 GTypeInfo typeinfo = {
1333 sizeof (GstFFMpegMuxClass),
1334 (GBaseInitFunc) gst_ffmpegmux_base_init,
1336 (GClassInitFunc) gst_ffmpegmux_class_init,
1339 sizeof (GstFFMpegMux),
1341 (GInstanceInitFunc) gst_ffmpegmux_init,
1343 static const GInterfaceInfo tag_setter_info = {
1347 const AVOutputFormat *in_plugin;
1350 GST_LOG ("Registering muxers");
1352 while ((in_plugin = av_muxer_iterate (&i))) {
1354 GstRank rank = GST_RANK_MARGINAL;
1356 if ((!strncmp (in_plugin->name, "u16", 3)) ||
1357 (!strncmp (in_plugin->name, "s16", 3)) ||
1358 (!strncmp (in_plugin->name, "u24", 3)) ||
1359 (!strncmp (in_plugin->name, "s24", 3)) ||
1360 (!strncmp (in_plugin->name, "u8", 2)) ||
1361 (!strncmp (in_plugin->name, "s8", 2)) ||
1362 (!strncmp (in_plugin->name, "u32", 3)) ||
1363 (!strncmp (in_plugin->name, "s32", 3)) ||
1364 (!strncmp (in_plugin->name, "f32", 3)) ||
1365 (!strncmp (in_plugin->name, "f64", 3)) ||
1366 (!strncmp (in_plugin->name, "raw", 3)) ||
1367 (!strncmp (in_plugin->name, "crc", 3)) ||
1368 (!strncmp (in_plugin->name, "null", 4)) ||
1369 (!strncmp (in_plugin->name, "gif", 3)) ||
1370 (!strncmp (in_plugin->name, "fifo", 4)) ||
1371 (!strncmp (in_plugin->name, "frame", 5)) ||
1372 (!strncmp (in_plugin->name, "image", 5)) ||
1373 (!strncmp (in_plugin->name, "mulaw", 5)) ||
1374 (!strncmp (in_plugin->name, "alaw", 4)) ||
1375 (!strncmp (in_plugin->name, "h26", 3)) ||
1376 (!strncmp (in_plugin->name, "rtp", 3)) ||
1377 (!strncmp (in_plugin->name, "ass", 3)) ||
1378 (!strncmp (in_plugin->name, "ffmetadata", 10)) ||
1379 (!strncmp (in_plugin->name, "srt", 3)) ||
1380 (!strncmp (in_plugin->name, "scc", 3)) ||
1381 !strcmp (in_plugin->name, "ttml") ||
1382 !strcmp (in_plugin->name, "segment") ||
1383 !strcmp (in_plugin->name, "stream_segment,ssegment") ||
1384 !strcmp (in_plugin->name, "jacosub") ||
1385 !strcmp (in_plugin->name, "webvtt") ||
1386 !strcmp (in_plugin->name, "lrc") ||
1387 !strcmp (in_plugin->name, "microdvd") ||
1388 !strcmp (in_plugin->name, "tee") ||
1389 !strncmp (in_plugin->name, "webm", 4)
1391 GST_LOG ("Ignoring muxer %s", in_plugin->name);
1395 if (in_plugin->long_name != NULL) {
1396 if ((!strncmp (in_plugin->long_name, "raw ", 4))) {
1397 GST_LOG ("Ignoring raw muxer %s", in_plugin->name);
1402 if (gst_ffmpegmux_get_replacement (in_plugin->name))
1403 rank = GST_RANK_NONE;
1405 /* FIXME : We need a fast way to know whether we have mappings for this
1408 /* construct the type */
1409 type_name = g_strdup_printf ("avmux_%s", in_plugin->name);
1410 g_strdelimit (type_name, ".,|-<> ", '_');
1412 type = g_type_from_name (type_name);
1415 /* create the type now */
1416 type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1417 g_type_set_qdata (type, GST_FFMUX_PARAMS_QDATA, (gpointer) in_plugin);
1418 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
1421 if (!gst_element_register (plugin, type_name, rank, type)) {
1429 GST_LOG ("Finished registering muxers");