static void gst_ffmpegenc_base_init (GstFFMpegEncClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); AVCodec *in_plugin; GstElementDetails details; GstPadTemplate *srctempl = NULL, *sinktempl = NULL; GstCaps *srccaps = NULL, *sinkcaps = NULL; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), GST_FFENC_PARAMS_QDATA); g_assert (in_plugin != NULL); /* construct the element details struct */ details.longname = g_strdup_printf ("FFmpeg %s encoder", in_plugin->long_name); details.klass = g_strdup_printf ("Codec/Encoder/%s", (in_plugin->type == CODEC_TYPE_VIDEO) ? "Video" : "Audio"); details.description = g_strdup_printf ("FFmpeg %s encoder", in_plugin->name); details.author = "Wim Taymans <*****@*****.**>, " "Ronald Bultje <*****@*****.**>"; gst_element_class_set_details (element_class, &details); g_free (details.longname); g_free (details.klass); g_free (details.description); if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) { GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name); srccaps = gst_caps_new_simple ("unknown/unknown", NULL); } if (in_plugin->type == CODEC_TYPE_VIDEO) { sinkcaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv; video/x-raw-gray"); } else { sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, in_plugin->id, TRUE, in_plugin); } if (!sinkcaps) { GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name); sinkcaps = gst_caps_new_simple ("unknown/unknown", NULL); } /* pad templates */ sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps); srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps); gst_element_class_add_pad_template (element_class, srctempl); gst_element_class_add_pad_template (element_class, sinktempl); klass->in_plugin = in_plugin; klass->srctempl = srctempl; klass->sinktempl = sinktempl; klass->sinkcaps = NULL; return; }
static void gst_ffmpegauddec_base_init (GstFFMpegAudDecClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstPadTemplate *sinktempl, *srctempl; GstCaps *sinkcaps, *srccaps; AVCodec *in_plugin; gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), GST_FFDEC_PARAMS_QDATA); g_assert (in_plugin != NULL); /* construct the element details struct */ longname = g_strdup_printf ("libav %s decoder", in_plugin->long_name); description = g_strdup_printf ("libav %s decoder", in_plugin->name); gst_element_class_set_metadata (element_class, longname, "Codec/Decoder/Audio", description, "Wim Taymans <*****@*****.**>, " "Ronald Bultje <*****@*****.**>, " "Edward Hervey <*****@*****.**>"); g_free (longname); g_free (description); /* get the caps */ sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE); if (!sinkcaps) { GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name); sinkcaps = gst_caps_from_string ("unknown/unknown"); } srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL, in_plugin->id, FALSE, in_plugin); if (!srccaps) { GST_DEBUG ("Couldn't get source caps for decoder '%s'", in_plugin->name); srccaps = gst_caps_from_string ("audio/x-raw"); } /* pad templates */ sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps); srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps); gst_element_class_add_pad_template (element_class, srctempl); gst_element_class_add_pad_template (element_class, sinktempl); gst_caps_unref (sinkcaps); gst_caps_unref (srccaps); klass->in_plugin = in_plugin; klass->srctempl = srctempl; klass->sinktempl = sinktempl; }
static void gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); AVCodec *in_plugin; GstPadTemplate *srctempl = NULL, *sinktempl = NULL; GstCaps *srccaps = NULL, *sinkcaps = NULL; gchar *longname, *description; in_plugin = (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), GST_FFENC_PARAMS_QDATA); g_assert (in_plugin != NULL); /* construct the element details struct */ longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name); description = g_strdup_printf ("libav %s encoder", in_plugin->name); gst_element_class_set_metadata (element_class, longname, "Codec/Encoder/Audio", description, "Wim Taymans <*****@*****.**>, " "Ronald Bultje <*****@*****.**>"); g_free (longname); g_free (description); if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) { GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name); srccaps = gst_caps_new_empty_simple ("unknown/unknown"); } sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, in_plugin->id, TRUE, in_plugin); if (!sinkcaps) { GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name); sinkcaps = gst_caps_new_empty_simple ("unknown/unknown"); } /* pad templates */ sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps); srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps); gst_element_class_add_pad_template (element_class, srctempl); gst_element_class_add_pad_template (element_class, sinktempl); klass->in_plugin = in_plugin; klass->srctempl = srctempl; klass->sinktempl = sinktempl; return; }
static GstCaps * gst_ffmpegmux_get_id_caps (enum CodecID *id_list) { GstCaps *caps, *t; gint i; caps = gst_caps_new_empty (); for (i = 0; id_list[i] != CODEC_ID_NONE; i++) { if ((t = gst_ffmpeg_codecid_to_caps (id_list[i], NULL, TRUE))) gst_caps_append (caps, t); } if (gst_caps_is_empty (caps)) { gst_caps_unref (caps); return NULL; } return caps; }
static gboolean gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) { GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; gsize frame_size; GstFFMpegAudEncClass *oclass = (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); /* close old session */ if (ffmpegaudenc->opened) { gst_ffmpeg_avcodec_close (ffmpegaudenc->context); ffmpegaudenc->opened = FALSE; } /* if we set it in _getcaps we should set it also in _link */ ffmpegaudenc->context->strict_std_compliance = -1; /* user defined properties */ if (ffmpegaudenc->bitrate > 0) { GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d", ffmpegaudenc->bitrate); ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate; ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate; } else { GST_INFO_OBJECT (ffmpegaudenc, "Using avcontext default bitrate %d", ffmpegaudenc->context->bit_rate); } /* RTP payload used for GOB production (for Asterisk) */ if (ffmpegaudenc->rtp_payload_size) { ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size; } /* some other defaults */ ffmpegaudenc->context->rc_strategy = 2; ffmpegaudenc->context->b_frame_strategy = 0; ffmpegaudenc->context->coder_type = 0; ffmpegaudenc->context->context_model = 0; ffmpegaudenc->context->scenechange_threshold = 0; ffmpegaudenc->context->inter_threshold = 0; /* fetch pix_fmt and so on */ gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context); if (!ffmpegaudenc->context->time_base.den) { ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info); ffmpegaudenc->context->time_base.num = 1; ffmpegaudenc->context->ticks_per_frame = 1; } if (ffmpegaudenc->context->channel_layout) { gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout, ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout); ffmpegaudenc->needs_reorder = (memcmp (ffmpegaudenc->ffmpeg_layout, info->position, sizeof (GstAudioChannelPosition) * ffmpegaudenc->context->channels) != 0); } /* open codec */ if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) { if (ffmpegaudenc->context->priv_data) gst_ffmpeg_avcodec_close (ffmpegaudenc->context); GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); return FALSE; } /* some codecs support more than one format, first auto-choose one */ GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ..."); allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); if (!allowed_caps) { GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps"); /* we need to copy because get_allowed_caps returns a ref, and * get_pad_template_caps doesn't */ allowed_caps = gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); } GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context); /* try to set this caps on the other side */ other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, ffmpegaudenc->context, TRUE); if (!other_caps) { gst_caps_unref (allowed_caps); gst_ffmpeg_avcodec_close (ffmpegaudenc->context); GST_DEBUG ("Unsupported codec - no caps found"); return FALSE; } icaps = gst_caps_intersect (allowed_caps, other_caps); gst_caps_unref (allowed_caps); gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { gst_caps_unref (icaps); return FALSE; } icaps = gst_caps_truncate (icaps); if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc), icaps)) { gst_ffmpeg_avcodec_close (ffmpegaudenc->context); gst_caps_unref (icaps); return FALSE; } gst_caps_unref (icaps); frame_size = ffmpegaudenc->context->frame_size; if (frame_size > 1) { gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), frame_size); gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), frame_size); gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1); } else { gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), 0); gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0); gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0); } /* success! */ ffmpegaudenc->opened = TRUE; return TRUE; }
static gboolean gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) { GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; gsize frame_size; GstFFMpegAudEncClass *oclass = (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); /* close old session */ if (ffmpegaudenc->opened) { gst_ffmpeg_avcodec_close (ffmpegaudenc->context); ffmpegaudenc->opened = FALSE; if (avcodec_get_context_defaults3 (ffmpegaudenc->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } } /* if we set it in _getcaps we should set it also in _link */ ffmpegaudenc->context->strict_std_compliance = ffmpegaudenc->compliance; /* user defined properties */ if (ffmpegaudenc->bitrate > 0) { GST_INFO_OBJECT (ffmpegaudenc, "Setting avcontext to bitrate %d", ffmpegaudenc->bitrate); ffmpegaudenc->context->bit_rate = ffmpegaudenc->bitrate; ffmpegaudenc->context->bit_rate_tolerance = ffmpegaudenc->bitrate; } else { GST_INFO_OBJECT (ffmpegaudenc, "Using avcontext default bitrate %" G_GINT64_FORMAT, (gint64) ffmpegaudenc->context->bit_rate); } /* RTP payload used for GOB production (for Asterisk) */ if (ffmpegaudenc->rtp_payload_size) { ffmpegaudenc->context->rtp_payload_size = ffmpegaudenc->rtp_payload_size; } /* some other defaults */ ffmpegaudenc->context->rc_strategy = 2; ffmpegaudenc->context->b_frame_strategy = 0; ffmpegaudenc->context->coder_type = 0; ffmpegaudenc->context->context_model = 0; ffmpegaudenc->context->scenechange_threshold = 0; /* fetch pix_fmt and so on */ gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context); if (!ffmpegaudenc->context->time_base.den) { ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info); ffmpegaudenc->context->time_base.num = 1; ffmpegaudenc->context->ticks_per_frame = 1; } if (ffmpegaudenc->context->channel_layout) { gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout, ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout); ffmpegaudenc->needs_reorder = (memcmp (ffmpegaudenc->ffmpeg_layout, info->position, sizeof (GstAudioChannelPosition) * ffmpegaudenc->context->channels) != 0); } /* some codecs support more than one format, first auto-choose one */ GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ..."); allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); if (!allowed_caps) { GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps"); /* we need to copy because get_allowed_caps returns a ref, and * get_pad_template_caps doesn't */ allowed_caps = gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); } GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context); /* open codec */ if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) { gst_caps_unref (allowed_caps); gst_ffmpeg_avcodec_close (ffmpegaudenc->context); GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); if (avcodec_get_context_defaults3 (ffmpegaudenc->context, oclass->in_plugin) < 0) GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); if ((oclass->in_plugin->capabilities & CODEC_CAP_EXPERIMENTAL) && ffmpegaudenc->compliance != GST_FFMPEG_EXPERIMENTAL) { GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS, ("Codec is experimental, but settings don't allow encoders to " "produce output of experimental quality"), ("This codec may not create output that is conformant to the specs " "or of good quality. If you must use it anyway, set the " "compliance property to experimental")); } return FALSE; } /* try to set this caps on the other side */ other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, ffmpegaudenc->context, TRUE); if (!other_caps) { gst_caps_unref (allowed_caps); gst_ffmpeg_avcodec_close (ffmpegaudenc->context); GST_DEBUG ("Unsupported codec - no caps found"); if (avcodec_get_context_defaults3 (ffmpegaudenc->context, oclass->in_plugin) < 0) GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } icaps = gst_caps_intersect (allowed_caps, other_caps); gst_caps_unref (allowed_caps); gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { gst_caps_unref (icaps); return FALSE; } icaps = gst_caps_fixate (icaps); if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc), icaps)) { gst_ffmpeg_avcodec_close (ffmpegaudenc->context); gst_caps_unref (icaps); if (avcodec_get_context_defaults3 (ffmpegaudenc->context, oclass->in_plugin) < 0) GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } gst_caps_unref (icaps); frame_size = ffmpegaudenc->context->frame_size; if (frame_size > 1) { gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), frame_size); gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), frame_size); gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1); } else { gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), 0); gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0); gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0); } /* Store some tags */ { GstTagList *tags = gst_tag_list_new_empty (); const gchar *codec; gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, (guint) ffmpegaudenc->context->bit_rate, NULL); if ((codec = gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id))) gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec, NULL); gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (tags); } /* success! */ ffmpegaudenc->opened = TRUE; return TRUE; }
static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps) { GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; enum PixelFormat pix_fmt; GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); GstFFMpegEncClass *oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); /* close old session */ if (ffmpegenc->opened) { gst_ffmpeg_avcodec_close (ffmpegenc->context); ffmpegenc->opened = FALSE; } /* set defaults */ avcodec_get_context_defaults (ffmpegenc->context); /* if we set it in _getcaps we should set it also in _link */ ffmpegenc->context->strict_std_compliance = -1; /* user defined properties */ ffmpegenc->context->bit_rate = ffmpegenc->bitrate; ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate; ffmpegenc->context->gop_size = ffmpegenc->gop_size; ffmpegenc->context->me_method = ffmpegenc->me_method; GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %lu, gop_size %d", ffmpegenc->bitrate, ffmpegenc->gop_size); /* RTP payload used for GOB production (for Asterisk) */ if (ffmpegenc->rtp_payload_size) { ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size; } /* additional avcodec settings */ /* first fill in the majority by copying over */ gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context); /* then handle some special cases */ ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5); ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5); if (ffmpegenc->interlaced) { ffmpegenc->context->flags |= CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME; ffmpegenc->picture->interlaced_frame = TRUE; /* if this is not the case, a filter element should be used to swap fields */ ffmpegenc->picture->top_field_first = TRUE; } /* some other defaults */ ffmpegenc->context->rc_strategy = 2; ffmpegenc->context->b_frame_strategy = 0; ffmpegenc->context->coder_type = 0; ffmpegenc->context->context_model = 0; ffmpegenc->context->scenechange_threshold = 0; ffmpegenc->context->inter_threshold = 0; /* and last but not least the pass; CBR, 2-pass, etc */ ffmpegenc->context->flags |= ffmpegenc->pass; switch (ffmpegenc->pass) { /* some additional action depends on type of pass */ case CODEC_FLAG_QSCALE: ffmpegenc->context->global_quality = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer; break; case CODEC_FLAG_PASS1: /* need to prepare a stats file */ /* we don't close when changing caps, fingers crossed */ if (!ffmpegenc->file) ffmpegenc->file = g_fopen (ffmpegenc->filename, "w"); if (!ffmpegenc->file) { GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE, (("Could not open file \"%s\" for writing."), ffmpegenc->filename), GST_ERROR_SYSTEM); return FALSE; } break; case CODEC_FLAG_PASS2: { /* need to read the whole stats file ! */ gsize size; if (!g_file_get_contents (ffmpegenc->filename, &ffmpegenc->context->stats_in, &size, NULL)) { GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ, (("Could not get contents of file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); return FALSE; } break; } default: break; } /* fetch pix_fmt and so on */ gst_ffmpeg_caps_with_codectype (oclass->in_plugin->type, caps, ffmpegenc->context); if (!ffmpegenc->context->time_base.den) { ffmpegenc->context->time_base.den = 25; ffmpegenc->context->time_base.num = 1; ffmpegenc->context->ticks_per_frame = 1; } else if ((oclass->in_plugin->id == CODEC_ID_MPEG4) && (ffmpegenc->context->time_base.den > 65535)) { /* MPEG4 Standards do not support time_base denominator greater than * (1<<16) - 1 . We therefore scale them down. * Agreed, it will not be the exact framerate... but the difference * shouldn't be that noticeable */ ffmpegenc->context->time_base.num = (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num, 65535, ffmpegenc->context->time_base.den); ffmpegenc->context->time_base.den = 65535; GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d", ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num); } pix_fmt = ffmpegenc->context->pix_fmt; /* max-key-interval may need the framerate set above */ if (ffmpegenc->max_key_interval) { AVCodecContext *ctx; /* override gop-size */ ctx = ffmpegenc->context; ctx->gop_size = (ffmpegenc->max_key_interval < 0) ? (-ffmpegenc->max_key_interval * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num)) : ffmpegenc->max_key_interval; } /* open codec */ if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) { if (ffmpegenc->context->priv_data) gst_ffmpeg_avcodec_close (ffmpegenc->context); if (ffmpegenc->context->stats_in) g_free (ffmpegenc->context->stats_in); GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); return FALSE; } /* second pass stats buffer no longer needed */ if (ffmpegenc->context->stats_in) g_free (ffmpegenc->context->stats_in); /* is the colourspace correct? */ if (pix_fmt != ffmpegenc->context->pix_fmt) { gst_ffmpeg_avcodec_close (ffmpegenc->context); GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: AV wants different colourspace (%d given, %d wanted)", oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt); return FALSE; } /* we may have failed mapping caps to a pixfmt, * and quite some codecs do not make up their own mind about that * in any case, _NONE can never work out later on */ if (oclass->in_plugin->type == CODEC_TYPE_VIDEO && pix_fmt == PIX_FMT_NONE) { GST_DEBUG_OBJECT (ffmpegenc, "ffenc_%s: Failed to determine input format", oclass->in_plugin->name); return FALSE; } /* some codecs support more than one format, first auto-choose one */ GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ..."); allowed_caps = gst_pad_get_allowed_caps (ffmpegenc->srcpad); if (!allowed_caps) { GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps"); /* we need to copy because get_allowed_caps returns a ref, and * get_pad_template_caps doesn't */ allowed_caps = gst_caps_copy (gst_pad_get_pad_template_caps (ffmpegenc->srcpad)); } GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, allowed_caps, ffmpegenc->context); /* try to set this caps on the other side */ other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, ffmpegenc->context, TRUE); if (!other_caps) { gst_ffmpeg_avcodec_close (ffmpegenc->context); GST_DEBUG ("Unsupported codec - no caps found"); return FALSE; } icaps = gst_caps_intersect (allowed_caps, other_caps); gst_caps_unref (allowed_caps); gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { gst_caps_unref (icaps); return FALSE; } if (gst_caps_get_size (icaps) > 1) { GstCaps *newcaps; newcaps = gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps, 0)), NULL); gst_caps_unref (icaps); icaps = newcaps; } if (!gst_pad_set_caps (ffmpegenc->srcpad, icaps)) { gst_ffmpeg_avcodec_close (ffmpegenc->context); gst_caps_unref (icaps); return FALSE; } gst_caps_unref (icaps); /* success! */ ffmpegenc->opened = TRUE; return TRUE; }
static gboolean gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state) { GstCaps *other_caps; GstCaps *allowed_caps; GstCaps *icaps; GstVideoCodecState *output_format; enum AVPixelFormat pix_fmt; GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; GstFFMpegVidEncClass *oclass = (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); /* close old session */ if (ffmpegenc->opened) { gst_ffmpeg_avcodec_close (ffmpegenc->context); ffmpegenc->opened = FALSE; if (avcodec_get_context_defaults3 (ffmpegenc->context, oclass->in_plugin) < 0) { GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); return FALSE; } } /* if we set it in _getcaps we should set it also in _link */ ffmpegenc->context->strict_std_compliance = ffmpegenc->compliance; /* user defined properties */ ffmpegenc->context->bit_rate = ffmpegenc->bitrate; ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate; ffmpegenc->context->gop_size = ffmpegenc->gop_size; ffmpegenc->context->me_method = ffmpegenc->me_method; GST_DEBUG_OBJECT (ffmpegenc, "Setting avcontext to bitrate %d, gop_size %d", ffmpegenc->bitrate, ffmpegenc->gop_size); if (ffmpegenc->max_threads == 0) { if (!(oclass->in_plugin->capabilities & CODEC_CAP_AUTO_THREADS)) ffmpegenc->context->thread_count = gst_ffmpeg_auto_max_threads (); else ffmpegenc->context->thread_count = 0; } else ffmpegenc->context->thread_count = ffmpegenc->max_threads; /* RTP payload used for GOB production (for Asterisk) */ if (ffmpegenc->rtp_payload_size) { ffmpegenc->context->rtp_payload_size = ffmpegenc->rtp_payload_size; } /* additional avcodec settings */ /* first fill in the majority by copying over */ gst_ffmpeg_cfg_fill_context (ffmpegenc, ffmpegenc->context); /* then handle some special cases */ ffmpegenc->context->lmin = (ffmpegenc->lmin * FF_QP2LAMBDA + 0.5); ffmpegenc->context->lmax = (ffmpegenc->lmax * FF_QP2LAMBDA + 0.5); if (ffmpegenc->interlaced) { ffmpegenc->context->flags |= CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME; } /* some other defaults */ ffmpegenc->context->rc_strategy = 2; ffmpegenc->context->b_frame_strategy = 0; ffmpegenc->context->coder_type = 0; ffmpegenc->context->context_model = 0; ffmpegenc->context->scenechange_threshold = 0; /* and last but not least the pass; CBR, 2-pass, etc */ ffmpegenc->context->flags |= ffmpegenc->pass; switch (ffmpegenc->pass) { /* some additional action depends on type of pass */ case CODEC_FLAG_QSCALE: ffmpegenc->context->global_quality = ffmpegenc->picture->quality = FF_QP2LAMBDA * ffmpegenc->quantizer; break; case CODEC_FLAG_PASS1: /* need to prepare a stats file */ /* we don't close when changing caps, fingers crossed */ if (!ffmpegenc->file) ffmpegenc->file = g_fopen (ffmpegenc->filename, "w"); if (!ffmpegenc->file) goto open_file_err; break; case CODEC_FLAG_PASS2: { /* need to read the whole stats file ! */ gsize size; if (!g_file_get_contents (ffmpegenc->filename, &ffmpegenc->context->stats_in, &size, NULL)) goto file_read_err; break; } default: break; } GST_DEBUG_OBJECT (ffmpegenc, "Extracting common video information"); /* fetch pix_fmt, fps, par, width, height... */ gst_ffmpeg_videoinfo_to_context (&state->info, ffmpegenc->context); /* sanitize time base */ if (ffmpegenc->context->time_base.num <= 0 || ffmpegenc->context->time_base.den <= 0) goto insane_timebase; if ((oclass->in_plugin->id == AV_CODEC_ID_MPEG4) && (ffmpegenc->context->time_base.den > 65535)) { /* MPEG4 Standards do not support time_base denominator greater than * (1<<16) - 1 . We therefore scale them down. * Agreed, it will not be the exact framerate... but the difference * shouldn't be that noticeable */ ffmpegenc->context->time_base.num = (gint) gst_util_uint64_scale_int (ffmpegenc->context->time_base.num, 65535, ffmpegenc->context->time_base.den); ffmpegenc->context->time_base.den = 65535; GST_LOG_OBJECT (ffmpegenc, "MPEG4 : scaled down framerate to %d / %d", ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num); } pix_fmt = ffmpegenc->context->pix_fmt; /* max-key-interval may need the framerate set above */ if (ffmpegenc->max_key_interval) { AVCodecContext *ctx; /* override gop-size */ ctx = ffmpegenc->context; ctx->gop_size = (ffmpegenc->max_key_interval < 0) ? (-ffmpegenc->max_key_interval * (ctx->time_base.den * ctx->ticks_per_frame / ctx->time_base.num)) : ffmpegenc->max_key_interval; } /* some codecs support more than one format, first auto-choose one */ GST_DEBUG_OBJECT (ffmpegenc, "picking an output format ..."); allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder)); if (!allowed_caps) { GST_DEBUG_OBJECT (ffmpegenc, "... but no peer, using template caps"); /* we need to copy because get_allowed_caps returns a ref, and * get_pad_template_caps doesn't */ allowed_caps = gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder)); } GST_DEBUG_OBJECT (ffmpegenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, allowed_caps, ffmpegenc->context); /* open codec */ if (gst_ffmpeg_avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) { gst_caps_unref (allowed_caps); goto open_codec_fail; } /* is the colourspace correct? */ if (pix_fmt != ffmpegenc->context->pix_fmt) { gst_caps_unref (allowed_caps); goto pix_fmt_err; } /* we may have failed mapping caps to a pixfmt, * and quite some codecs do not make up their own mind about that * in any case, _NONE can never work out later on */ if (pix_fmt == AV_PIX_FMT_NONE) { gst_caps_unref (allowed_caps); goto bad_input_fmt; } /* second pass stats buffer no longer needed */ g_free (ffmpegenc->context->stats_in); /* try to set this caps on the other side */ other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, ffmpegenc->context, TRUE); if (!other_caps) { gst_caps_unref (allowed_caps); goto unsupported_codec; } icaps = gst_caps_intersect (allowed_caps, other_caps); gst_caps_unref (allowed_caps); gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { gst_caps_unref (icaps); goto unsupported_codec; } icaps = gst_caps_fixate (icaps); GST_DEBUG_OBJECT (ffmpegenc, "codec flags 0x%08x", ffmpegenc->context->flags); /* Store input state and set output state */ if (ffmpegenc->input_state) gst_video_codec_state_unref (ffmpegenc->input_state); ffmpegenc->input_state = gst_video_codec_state_ref (state); output_format = gst_video_encoder_set_output_state (encoder, icaps, state); gst_video_codec_state_unref (output_format); /* Store some tags */ { GstTagList *tags = gst_tag_list_new_empty (); const gchar *codec; gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, (guint) ffmpegenc->context->bit_rate, NULL); if ((codec = gst_ffmpeg_get_codecid_longname (ffmpegenc->context->codec_id))) gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_VIDEO_CODEC, codec, NULL); gst_video_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE); gst_tag_list_unref (tags); } /* success! */ ffmpegenc->opened = TRUE; return TRUE; /* ERRORS */ open_file_err: { GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE, (("Could not open file \"%s\" for writing."), ffmpegenc->filename), GST_ERROR_SYSTEM); return FALSE; } file_read_err: { GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ, (("Could not get contents of file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); return FALSE; } insane_timebase: { GST_ERROR_OBJECT (ffmpegenc, "Rejecting time base %d/%d", ffmpegenc->context->time_base.den, ffmpegenc->context->time_base.num); goto cleanup_stats_in; } unsupported_codec: { GST_DEBUG ("Unsupported codec - no caps found"); goto cleanup_stats_in; } open_codec_fail: { GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to open libav codec", oclass->in_plugin->name); goto close_codec; } pix_fmt_err: { GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: AV wants different colourspace (%d given, %d wanted)", oclass->in_plugin->name, pix_fmt, ffmpegenc->context->pix_fmt); goto close_codec; } bad_input_fmt: { GST_DEBUG_OBJECT (ffmpegenc, "avenc_%s: Failed to determine input format", oclass->in_plugin->name); goto close_codec; } close_codec: { gst_ffmpeg_avcodec_close (ffmpegenc->context); if (avcodec_get_context_defaults3 (ffmpegenc->context, oclass->in_plugin) < 0) GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); goto cleanup_stats_in; } cleanup_stats_in: { g_free (ffmpegenc->context->stats_in); return FALSE; } }