/* with LOCK */ static gboolean gst_ffmpegauddec_open (GstFFMpegAudDec * ffmpegdec) { GstFFMpegAudDecClass *oclass; oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); if (gst_ffmpeg_avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) goto could_not_open; ffmpegdec->opened = TRUE; GST_LOG_OBJECT (ffmpegdec, "Opened libav codec %s, id %d", oclass->in_plugin->name, oclass->in_plugin->id); gst_audio_info_init (&ffmpegdec->info); return TRUE; /* ERRORS */ could_not_open: { gst_ffmpegauddec_close (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec", oclass->in_plugin->name); return FALSE; } }
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 GstCaps * gst_ffmpegenc_getcaps (GstPad * pad) { GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); GstFFMpegEncClass *oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); AVCodecContext *ctx = NULL; enum PixelFormat pixfmt; GstCaps *caps = NULL; gint i; GST_DEBUG_OBJECT (ffmpegenc, "getting caps"); /* audio needs no special care */ if (oclass->in_plugin->type == CODEC_TYPE_AUDIO) { caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); GST_DEBUG_OBJECT (ffmpegenc, "audio caps, return template %" GST_PTR_FORMAT, caps); return caps; } /* cached */ if (oclass->sinkcaps) { caps = gst_caps_copy (oclass->sinkcaps); GST_DEBUG_OBJECT (ffmpegenc, "return cached caps %" GST_PTR_FORMAT, caps); return caps; } /* create cache etc. */ /* shut up the logging while we autoprobe; we don't want warnings and * errors about unsupported formats */ /* FIXME: if someone cares about this disabling the logging for other * instances/threads/..., one could investigate if there is a way to * set this as a struct member on the av context, and check it from the * log handler */ #ifndef GST_DISABLE_GST_DEBUG _shut_up_I_am_probing = TRUE; #endif GST_DEBUG_OBJECT (ffmpegenc, "probing caps"); i = pixfmt = 0; /* check pixfmt until deemed finished */ for (pixfmt = 0;; pixfmt++) { GstCaps *tmpcaps; /* override looping all pixfmt if codec declares pixfmts; * these may not properly check and report supported pixfmt during _init */ if (oclass->in_plugin->pix_fmts) { if ((pixfmt = oclass->in_plugin->pix_fmts[i++]) == PIX_FMT_NONE) { GST_DEBUG_OBJECT (ffmpegenc, "At the end of official pixfmt for this codec, breaking out"); break; } GST_DEBUG_OBJECT (ffmpegenc, "Got an official pixfmt [%d], attempting to get caps", pixfmt); tmpcaps = gst_ffmpeg_pixfmt_to_caps (pixfmt, NULL, oclass->in_plugin->id); if (tmpcaps) { GST_DEBUG_OBJECT (ffmpegenc, "Got caps, breaking out"); if (!caps) caps = gst_caps_new_empty (); gst_caps_append (caps, tmpcaps); continue; } GST_DEBUG_OBJECT (ffmpegenc, "Couldn't figure out caps without context, trying again with a context"); } GST_DEBUG_OBJECT (ffmpegenc, "pixfmt :%d", pixfmt); if (pixfmt >= PIX_FMT_NB) { GST_WARNING ("Invalid pixfmt, breaking out"); break; } /* need to start with a fresh codec_context each time around, since * codec_close may have released stuff causing the next pass to segfault */ ctx = avcodec_alloc_context (); if (!ctx) { GST_DEBUG_OBJECT (ffmpegenc, "no context"); break; } /* set some default properties */ ctx->width = DEFAULT_WIDTH; ctx->height = DEFAULT_HEIGHT; ctx->time_base.num = 1; ctx->time_base.den = 25; ctx->ticks_per_frame = 1; ctx->bit_rate = DEFAULT_VIDEO_BITRATE; /* makes it silent */ ctx->strict_std_compliance = -1; ctx->pix_fmt = pixfmt; GST_DEBUG ("Attempting to open codec"); if (gst_ffmpeg_avcodec_open (ctx, oclass->in_plugin) >= 0 && ctx->pix_fmt == pixfmt) { ctx->width = -1; if (!caps) caps = gst_caps_new_empty (); tmpcaps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ctx, oclass->in_plugin->id, TRUE); if (tmpcaps) gst_caps_append (caps, tmpcaps); else GST_LOG_OBJECT (ffmpegenc, "Couldn't get caps for oclass->in_plugin->name:%s", oclass->in_plugin->name); gst_ffmpeg_avcodec_close (ctx); } else { GST_DEBUG_OBJECT (ffmpegenc, "Opening codec failed with pixfmt : %d", pixfmt); } if (ctx->priv_data) gst_ffmpeg_avcodec_close (ctx); av_free (ctx); } #ifndef GST_DISABLE_GST_DEBUG _shut_up_I_am_probing = FALSE; #endif /* make sure we have something */ if (!caps) { caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); GST_DEBUG_OBJECT (ffmpegenc, "probing gave nothing, " "return template %" GST_PTR_FORMAT, caps); return caps; } GST_DEBUG_OBJECT (ffmpegenc, "probed caps gave %" GST_PTR_FORMAT, caps); oclass->sinkcaps = gst_caps_copy (caps); return caps; }
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; } }