From 73d0cac16cc8faf47064160857c24fae485d6876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com> Date: Wed, 1 May 2024 13:56:56 +0300 Subject: [PATCH] libav: Update AVCodecContext lifetime to work properly with ffmpeg 7 avcodec_close() is deprecated and it's not supported anymore to re-open a codec, so we only ever allocate the codec in set_format() now and always free it after usage. As part of this, also fix various memory leaks in related code paths. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6505> --- subprojects/gst-libav/ext/libav/gstav.c | 12 --- subprojects/gst-libav/ext/libav/gstav.h | 1 - subprojects/gst-libav/ext/libav/gstavauddec.c | 92 ++++++------------ subprojects/gst-libav/ext/libav/gstavauddec.h | 1 - subprojects/gst-libav/ext/libav/gstavaudenc.c | 65 +++++-------- subprojects/gst-libav/ext/libav/gstavaudenc.h | 1 - subprojects/gst-libav/ext/libav/gstavcfg.c | 6 +- .../gst-libav/ext/libav/gstavdeinterlace.c | 5 +- subprojects/gst-libav/ext/libav/gstavviddec.c | 93 +++++++++---------- subprojects/gst-libav/ext/libav/gstavviddec.h | 1 - subprojects/gst-libav/ext/libav/gstavvidenc.c | 93 +++++++++---------- subprojects/gst-libav/ext/libav/gstavvidenc.h | 1 - 12 files changed, 143 insertions(+), 228 deletions(-) diff --git a/subprojects/gst-libav/ext/libav/gstav.c b/subprojects/gst-libav/ext/libav/gstav.c index 00fcc63881..0c9353f0c1 100644 --- a/subprojects/gst-libav/ext/libav/gstav.c +++ b/subprojects/gst-libav/ext/libav/gstav.c @@ -72,18 +72,6 @@ gst_ffmpeg_avcodec_open (AVCodecContext * avctx, const AVCodec * codec) return ret; } -int -gst_ffmpeg_avcodec_close (AVCodecContext * avctx) -{ - int ret; - - g_mutex_lock (&gst_avcodec_mutex); - ret = avcodec_close (avctx); - g_mutex_unlock (&gst_avcodec_mutex); - - return ret; -} - int gst_ffmpeg_av_find_stream_info (AVFormatContext * ic) { diff --git a/subprojects/gst-libav/ext/libav/gstav.h b/subprojects/gst-libav/ext/libav/gstav.h index a7fbb019fd..9cdb14503c 100644 --- a/subprojects/gst-libav/ext/libav/gstav.h +++ b/subprojects/gst-libav/ext/libav/gstav.h @@ -46,7 +46,6 @@ extern gboolean gst_ffmpegdeinterlace_register (GstPlugin * plugin); extern gboolean gst_ffmpegvidcmp_register (GstPlugin * plugin); int gst_ffmpeg_avcodec_open (AVCodecContext *avctx, const AVCodec *codec); -int gst_ffmpeg_avcodec_close (AVCodecContext *avctx); int gst_ffmpeg_av_find_stream_info(AVFormatContext *ic); G_END_DECLS diff --git a/subprojects/gst-libav/ext/libav/gstavauddec.c b/subprojects/gst-libav/ext/libav/gstavauddec.c index 48c4be6b6a..2279e690ee 100644 --- a/subprojects/gst-libav/ext/libav/gstavauddec.c +++ b/subprojects/gst-libav/ext/libav/gstavauddec.c @@ -145,16 +145,6 @@ gst_ffmpegauddec_class_init (GstFFMpegAudDecClass * klass) static void gst_ffmpegauddec_init (GstFFMpegAudDec * ffmpegdec) { - GstFFMpegAudDecClass *klass = - (GstFFMpegAudDecClass *) G_OBJECT_GET_CLASS (ffmpegdec); - - /* some ffmpeg data */ - ffmpegdec->context = avcodec_alloc_context3 (klass->in_plugin); - ffmpegdec->context->opaque = ffmpegdec; - ffmpegdec->opened = FALSE; - - ffmpegdec->frame = av_frame_alloc (); - GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_DECODER_SINK_PAD (ffmpegdec)); gst_audio_decoder_set_use_default_pad_acceptcaps (GST_AUDIO_DECODER_CAST (ffmpegdec), TRUE); @@ -175,60 +165,24 @@ gst_ffmpegauddec_finalize (GObject * object) } /* With LOCK */ -static gboolean -gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec, gboolean reset) +static void +gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec) { - GstFFMpegAudDecClass *oclass; - - oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); - GST_LOG_OBJECT (ffmpegdec, "closing libav codec"); gst_caps_replace (&ffmpegdec->last_caps, NULL); - - gst_ffmpeg_avcodec_close (ffmpegdec->context); - ffmpegdec->opened = FALSE; - av_freep (&ffmpegdec->context->extradata); - - if (reset) { - avcodec_free_context (&ffmpegdec->context); - ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegdec->context == NULL) { - GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); - return FALSE; - } - ffmpegdec->context->opaque = ffmpegdec; - } - - return TRUE; + avcodec_free_context (&ffmpegdec->context); } static gboolean gst_ffmpegauddec_start (GstAudioDecoder * decoder) { GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder; - GstFFMpegAudDecClass *oclass; - - oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GST_OBJECT_LOCK (ffmpegdec); + ffmpegdec->frame = av_frame_alloc (); avcodec_free_context (&ffmpegdec->context); - ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegdec->context == NULL) { - GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); - GST_OBJECT_UNLOCK (ffmpegdec); - return FALSE; - } - ffmpegdec->context->opaque = ffmpegdec; - - /* FIXME: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1474 */ - if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) != 0 - && (oclass->in_plugin->id == AV_CODEC_ID_WMAV1 - || oclass->in_plugin->id == AV_CODEC_ID_WMAV2)) { - ffmpegdec->context->flags2 |= AV_CODEC_FLAG2_SKIP_MANUAL; - } - GST_OBJECT_UNLOCK (ffmpegdec); return TRUE; @@ -240,8 +194,9 @@ gst_ffmpegauddec_stop (GstAudioDecoder * decoder) GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder; GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegauddec_close (ffmpegdec, FALSE); + av_frame_free (&ffmpegdec->frame); g_free (ffmpegdec->padded); + gst_ffmpegauddec_close (ffmpegdec); ffmpegdec->padded = NULL; ffmpegdec->padded_size = 0; GST_OBJECT_UNLOCK (ffmpegdec); @@ -262,8 +217,6 @@ gst_ffmpegauddec_open (GstFFMpegAudDec * 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); @@ -274,7 +227,7 @@ gst_ffmpegauddec_open (GstFFMpegAudDec * ffmpegdec) /* ERRORS */ could_not_open: { - gst_ffmpegauddec_close (ffmpegdec, TRUE); + gst_ffmpegauddec_close (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec", oclass->in_plugin->name); return FALSE; @@ -321,14 +274,26 @@ gst_ffmpegauddec_set_format (GstAudioDecoder * decoder, GstCaps * caps) gst_caps_replace (&ffmpegdec->last_caps, caps); /* close old session */ - if (ffmpegdec->opened) { + if (ffmpegdec->context) { GST_OBJECT_UNLOCK (ffmpegdec); gst_ffmpegauddec_drain (ffmpegdec, FALSE); GST_OBJECT_LOCK (ffmpegdec); - if (!gst_ffmpegauddec_close (ffmpegdec, TRUE)) { - GST_OBJECT_UNLOCK (ffmpegdec); - return FALSE; - } + gst_ffmpegauddec_close (ffmpegdec); + } + + ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); + if (ffmpegdec->context == NULL) { + GST_DEBUG_OBJECT (ffmpegdec, "Failed to allocate context"); + GST_OBJECT_UNLOCK (ffmpegdec); + return FALSE; + } + ffmpegdec->context->opaque = ffmpegdec; + + /* FIXME: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1474 */ + if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) != 0 + && (oclass->in_plugin->id == AV_CODEC_ID_WMAV1 + || oclass->in_plugin->id == AV_CODEC_ID_WMAV2)) { + ffmpegdec->context->flags2 |= AV_CODEC_FLAG2_SKIP_MANUAL; } /* get size and so */ @@ -586,7 +551,7 @@ gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, GstFlowReturn * ret, GstBuffer *outbuf = NULL; gboolean got_frame = FALSE; - if (G_UNLIKELY (ffmpegdec->context->codec == NULL)) + if (G_UNLIKELY (!ffmpegdec->context)) goto no_codec; *ret = GST_FLOW_OK; @@ -630,6 +595,9 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec, gboolean force) gboolean need_more_data = FALSE; gboolean got_frame; + if (!ffmpegdec->context) + return GST_FLOW_OK; + if (avcodec_send_packet (ffmpegdec->context, NULL)) goto send_packet_failed; @@ -672,7 +640,7 @@ gst_ffmpegauddec_flush (GstAudioDecoder * decoder, gboolean hard) { GstFFMpegAudDec *ffmpegdec = (GstFFMpegAudDec *) decoder; - if (ffmpegdec->opened) { + if (ffmpegdec->context) { avcodec_flush_buffers (ffmpegdec->context); } } @@ -697,7 +665,7 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) ffmpegdec = (GstFFMpegAudDec *) decoder; - if (G_UNLIKELY (!ffmpegdec->opened)) + if (G_UNLIKELY (!ffmpegdec->context)) goto not_negotiated; if (inbuf == NULL) { diff --git a/subprojects/gst-libav/ext/libav/gstavauddec.h b/subprojects/gst-libav/ext/libav/gstavauddec.h index d91de0d2b2..93466ad99f 100644 --- a/subprojects/gst-libav/ext/libav/gstavauddec.h +++ b/subprojects/gst-libav/ext/libav/gstavauddec.h @@ -34,7 +34,6 @@ struct _GstFFMpegAudDec /* decoding */ AVCodecContext *context; - gboolean opened; AVFrame *frame; diff --git a/subprojects/gst-libav/ext/libav/gstavaudenc.c b/subprojects/gst-libav/ext/libav/gstavaudenc.c index 57f41fe617..6ff966d32c 100644 --- a/subprojects/gst-libav/ext/libav/gstavaudenc.c +++ b/subprojects/gst-libav/ext/libav/gstavaudenc.c @@ -161,10 +161,7 @@ gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc) GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc)); /* ffmpeg objects */ - ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin); ffmpegaudenc->refcontext = avcodec_alloc_context3 (klass->in_plugin); - ffmpegaudenc->opened = FALSE; - ffmpegaudenc->frame = av_frame_alloc (); gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE); } @@ -186,18 +183,12 @@ static gboolean gst_ffmpegaudenc_start (GstAudioEncoder * encoder) { GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; - GstFFMpegAudEncClass *oclass = - (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); - - ffmpegaudenc->opened = FALSE; - ffmpegaudenc->need_reopen = FALSE; avcodec_free_context (&ffmpegaudenc->context); - ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegaudenc->context == NULL) { - GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); - return FALSE; - } + av_frame_free (&ffmpegaudenc->frame); + ffmpegaudenc->need_reopen = FALSE; + + ffmpegaudenc->frame = av_frame_alloc (); return TRUE; } @@ -208,8 +199,8 @@ gst_ffmpegaudenc_stop (GstAudioEncoder * encoder) GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; /* close old session */ - gst_ffmpeg_avcodec_close (ffmpegaudenc->context); - ffmpegaudenc->opened = FALSE; + avcodec_free_context (&ffmpegaudenc->context); + av_frame_free (&ffmpegaudenc->frame); ffmpegaudenc->need_reopen = FALSE; return TRUE; @@ -220,7 +211,7 @@ gst_ffmpegaudenc_flush (GstAudioEncoder * encoder) { GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; - if (ffmpegaudenc->opened) { + if (ffmpegaudenc->context) { avcodec_flush_buffers (ffmpegaudenc->context); } } @@ -239,14 +230,11 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) ffmpegaudenc->need_reopen = FALSE; /* close old session */ - if (ffmpegaudenc->opened) { - avcodec_free_context (&ffmpegaudenc->context); - ffmpegaudenc->opened = FALSE; - ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegaudenc->context == NULL) { - GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); - return FALSE; - } + avcodec_free_context (&ffmpegaudenc->context); + ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); + if (ffmpegaudenc->context == NULL) { + GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); + return FALSE; } gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context); @@ -298,12 +286,8 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) /* open codec */ if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) { gst_caps_unref (allowed_caps); - avcodec_free_context (&ffmpegaudenc->context); GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec", oclass->in_plugin->name); - ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegaudenc->context == NULL) - GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) && ffmpegaudenc->context->strict_std_compliance != @@ -315,6 +299,7 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) "or of good quality. If you must use it anyway, set the " "compliance property to experimental")); } + avcodec_free_context (&ffmpegaudenc->context); return FALSE; } @@ -326,9 +311,6 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) gst_caps_unref (allowed_caps); avcodec_free_context (&ffmpegaudenc->context); GST_DEBUG ("Unsupported codec - no caps found"); - ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegaudenc->context == NULL) - GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } @@ -337,6 +319,7 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { gst_caps_unref (icaps); + avcodec_free_context (&ffmpegaudenc->context); return FALSE; } icaps = gst_caps_fixate (icaps); @@ -345,9 +328,6 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) icaps)) { avcodec_free_context (&ffmpegaudenc->context); gst_caps_unref (icaps); - ffmpegaudenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegaudenc->context == NULL) - GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); return FALSE; } gst_caps_unref (icaps); @@ -385,8 +365,6 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) } /* success! */ - ffmpegaudenc->opened = TRUE; - ffmpegaudenc->need_reopen = FALSE; return TRUE; } @@ -394,8 +372,7 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) static void gst_ffmpegaudenc_free_avpacket (gpointer pkt) { - av_packet_unref ((AVPacket *) pkt); - g_free (pkt); + av_packet_free ((AVPacket **) & pkt); } typedef struct @@ -596,8 +573,7 @@ gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc, ctx = ffmpegaudenc->context; - pkt = g_new0 (AVPacket, 1); - + pkt = av_packet_alloc (); res = avcodec_receive_packet (ctx, pkt); if (res == 0) { @@ -636,7 +612,7 @@ gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc, *got_packet = TRUE; } else { GST_LOG_OBJECT (ffmpegaudenc, "no output produced"); - g_free (pkt); + av_packet_free (&pkt); ret = GST_FLOW_OK; *got_packet = FALSE; } @@ -650,6 +626,9 @@ gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc) GstFlowReturn ret = GST_FLOW_OK; gboolean got_packet; + if (!ffmpegaudenc->context) + return GST_FLOW_OK; + ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL); if (ret == GST_FLOW_OK) { @@ -683,7 +662,7 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf) ffmpegaudenc = (GstFFMpegAudEnc *) encoder; - if (G_UNLIKELY (!ffmpegaudenc->opened)) + if (G_UNLIKELY (!ffmpegaudenc->context)) goto not_negotiated; if (!inbuf) @@ -752,7 +731,7 @@ gst_ffmpegaudenc_set_property (GObject * object, ffmpegaudenc = (GstFFMpegAudEnc *) (object); - if (ffmpegaudenc->opened) { + if (ffmpegaudenc->context) { GST_WARNING_OBJECT (ffmpegaudenc, "Can't change properties once encoder is setup !"); return; diff --git a/subprojects/gst-libav/ext/libav/gstavaudenc.h b/subprojects/gst-libav/ext/libav/gstavaudenc.h index 3c94aef4e0..e21de8337d 100644 --- a/subprojects/gst-libav/ext/libav/gstavaudenc.h +++ b/subprojects/gst-libav/ext/libav/gstavaudenc.h @@ -38,7 +38,6 @@ struct _GstFFMpegAudEnc AVCodecContext *context; AVCodecContext *refcontext; - gboolean opened; gboolean need_reopen; AVFrame *frame; diff --git a/subprojects/gst-libav/ext/libav/gstavcfg.c b/subprojects/gst-libav/ext/libav/gstavcfg.c index bcc501c39c..6092b086c4 100644 --- a/subprojects/gst-libav/ext/libav/gstavcfg.c +++ b/subprojects/gst-libav/ext/libav/gstavcfg.c @@ -488,10 +488,8 @@ gst_ffmpeg_cfg_install_properties (GObjectClass * klass, AVCodec * in_plugin, install_opts ((GObjectClass *) klass, &ctx->av_class, prop_id, flags, " (Generic codec option, might have no effect)", generic_overrides); - if (ctx) { - gst_ffmpeg_avcodec_close (ctx); - av_free (ctx); - } + if (ctx) + avcodec_free_context (&ctx); } static gint diff --git a/subprojects/gst-libav/ext/libav/gstavdeinterlace.c b/subprojects/gst-libav/ext/libav/gstavdeinterlace.c index 2d46c50901..49dcdffb49 100644 --- a/subprojects/gst-libav/ext/libav/gstavdeinterlace.c +++ b/subprojects/gst-libav/ext/libav/gstavdeinterlace.c @@ -225,14 +225,13 @@ gst_ffmpegdeinterlace_sink_setcaps (GstPad * pad, GstObject * parent, ctx->pix_fmt = AV_PIX_FMT_NB; gst_ffmpeg_caps_with_codectype (AVMEDIA_TYPE_VIDEO, caps, ctx); if (ctx->pix_fmt == AV_PIX_FMT_NB) { - gst_ffmpeg_avcodec_close (ctx); - av_free (ctx); + avcodec_free_context (&ctx); return FALSE; } deinterlace->pixfmt = ctx->pix_fmt; - av_free (ctx); + avcodec_free_context (&ctx); deinterlace->to_size = av_image_get_buffer_size (deinterlace->pixfmt, deinterlace->width, diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.c b/subprojects/gst-libav/ext/libav/gstavviddec.c index 576e96ee2a..f131e99c94 100644 --- a/subprojects/gst-libav/ext/libav/gstavviddec.c +++ b/subprojects/gst-libav/ext/libav/gstavviddec.c @@ -337,14 +337,7 @@ gst_ffmpegviddec_init (GstFFMpegVidDec * ffmpegdec) static void gst_ffmpegviddec_subinit (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegVidDecClass *klass = - (GstFFMpegVidDecClass *) G_OBJECT_GET_CLASS (ffmpegdec); - /* some ffmpeg data */ - ffmpegdec->context = avcodec_alloc_context3 (klass->in_plugin); - ffmpegdec->context->opaque = ffmpegdec; - ffmpegdec->picture = av_frame_alloc (); - ffmpegdec->opened = FALSE; ffmpegdec->skip_frame = ffmpegdec->lowres = 0; ffmpegdec->direct_rendering = DEFAULT_DIRECT_RENDERING; ffmpegdec->max_threads = DEFAULT_MAX_THREADS; @@ -365,6 +358,8 @@ gst_ffmpegviddec_finalize (GObject * object) GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (object); av_frame_free (&ffmpegdec->picture); + if (ffmpegdec->context) + av_freep (&ffmpegdec->context->extradata); avcodec_free_context (&ffmpegdec->context); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -395,37 +390,23 @@ gst_ffmpegviddec_context_set_flags2 (AVCodecContext * context, guint flags, } /* with LOCK */ -static gboolean -gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec, gboolean reset) +static void +gst_ffmpegviddec_close (GstFFMpegVidDec * ffmpegdec) { - GstFFMpegVidDecClass *oclass; guint i; - oclass = GST_FFMPEGVIDDEC_GET_CLASS (ffmpegdec); - GST_LOG_OBJECT (ffmpegdec, "closing ffmpeg codec"); gst_caps_replace (&ffmpegdec->last_caps, NULL); - gst_ffmpeg_avcodec_close (ffmpegdec->context); - ffmpegdec->opened = FALSE; + if (ffmpegdec->context) + av_freep (&ffmpegdec->context->extradata); + avcodec_free_context (&ffmpegdec->context); for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++) ffmpegdec->stride[i] = -1; gst_buffer_replace (&ffmpegdec->palette, NULL); - - av_freep (&ffmpegdec->context->extradata); - if (reset) { - avcodec_free_context (&ffmpegdec->context); - ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegdec->context == NULL) { - GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); - return FALSE; - } - ffmpegdec->context->opaque = ffmpegdec; - } - return TRUE; } /* with LOCK */ @@ -443,8 +424,6 @@ gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec) for (i = 0; i < G_N_ELEMENTS (ffmpegdec->stride); i++) ffmpegdec->stride[i] = -1; - ffmpegdec->opened = TRUE; - GST_LOG_OBJECT (ffmpegdec, "Opened libav codec %s, id %d", oclass->in_plugin->name, oclass->in_plugin->id); @@ -460,7 +439,7 @@ gst_ffmpegviddec_open (GstFFMpegVidDec * ffmpegdec) /* ERRORS */ could_not_open: { - gst_ffmpegviddec_close (ffmpegdec, TRUE); + gst_ffmpegviddec_close (ffmpegdec); GST_DEBUG_OBJECT (ffmpegdec, "avdec_%s: Failed to open libav codec", oclass->in_plugin->name); return FALSE; @@ -537,14 +516,11 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, } /* close old session */ - if (ffmpegdec->opened) { + if (ffmpegdec->context) { GST_OBJECT_UNLOCK (ffmpegdec); gst_ffmpegviddec_finish (decoder); GST_OBJECT_LOCK (ffmpegdec); - if (!gst_ffmpegviddec_close (ffmpegdec, TRUE)) { - GST_OBJECT_UNLOCK (ffmpegdec); - return FALSE; - } + gst_ffmpegviddec_close (ffmpegdec); ffmpegdec->pic_pix_fmt = 0; ffmpegdec->pic_width = 0; ffmpegdec->pic_height = 0; @@ -560,6 +536,14 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, ffmpegdec->cur_multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE; } + ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); + if (ffmpegdec->context == NULL) { + GST_DEBUG_OBJECT (ffmpegdec, "Failed to allocate context"); + GST_OBJECT_UNLOCK (ffmpegdec); + return FALSE; + } + ffmpegdec->context->opaque = ffmpegdec; + gst_caps_replace (&ffmpegdec->last_caps, state->caps); /* set buffer functions */ @@ -718,12 +702,18 @@ done: open_failed: { GST_DEBUG_OBJECT (ffmpegdec, "Failed to open"); + if (ffmpegdec->context) + av_freep (&ffmpegdec->context->extradata); + avcodec_free_context (&ffmpegdec->context); goto done; } nal_only_slice: { GST_ERROR_OBJECT (ffmpegdec, "Can't do NAL aligned H.264 with frame threading."); + if (ffmpegdec->context) + av_freep (&ffmpegdec->context->extradata); + avcodec_free_context (&ffmpegdec->context); goto done; } } @@ -1848,7 +1838,7 @@ gst_ffmpegviddec_video_frame (GstFFMpegVidDec * ffmpegdec, GstFFMpegVidDecVideoFrame *out_dframe; GstBufferPool *pool; - if (G_UNLIKELY (ffmpegdec->context->codec == NULL)) + if (G_UNLIKELY (!ffmpegdec->context)) goto no_codec; #if LIBAVCODEC_VERSION_MAJOR >= 60 @@ -2141,7 +2131,7 @@ gst_ffmpegviddec_drain (GstVideoDecoder * decoder) GstFlowReturn ret = GST_FLOW_OK; gboolean got_frame = FALSE; - if (!ffmpegdec->opened) + if (!ffmpegdec->context) return GST_FLOW_OK; GST_VIDEO_DECODER_STREAM_UNLOCK (ffmpegdec); @@ -2187,6 +2177,12 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder, GstFlowReturn ret = GST_FLOW_OK; AVPacket *packet; + if (G_UNLIKELY (!ffmpegdec->context)) { + gst_video_codec_frame_unref (frame); + GST_ERROR_OBJECT (ffmpegdec, "no codec context"); + return GST_FLOW_NOT_NEGOTIATED; + } + GST_LOG_OBJECT (ffmpegdec, "Received new data of size %" G_GSIZE_FORMAT ", dts %" GST_TIME_FORMAT ", pts:%" GST_TIME_FORMAT ", dur:%" GST_TIME_FORMAT, @@ -2196,6 +2192,7 @@ gst_ffmpegviddec_handle_frame (GstVideoDecoder * decoder, if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) { GST_ELEMENT_ERROR (ffmpegdec, STREAM, DECODE, ("Decoding problem"), ("Failed to map buffer for reading")); + gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } @@ -2304,19 +2301,13 @@ static gboolean gst_ffmpegviddec_start (GstVideoDecoder * decoder) { GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder); - GstFFMpegVidDecClass *oclass; - - oclass = GST_FFMPEGVIDDEC_GET_CLASS (ffmpegdec); GST_OBJECT_LOCK (ffmpegdec); + av_frame_free (&ffmpegdec->picture); + if (ffmpegdec->context) + av_freep (&ffmpegdec->context->extradata); avcodec_free_context (&ffmpegdec->context); - ffmpegdec->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegdec->context == NULL) { - GST_DEBUG_OBJECT (ffmpegdec, "Failed to set context defaults"); - GST_OBJECT_UNLOCK (ffmpegdec); - return FALSE; - } - ffmpegdec->context->opaque = ffmpegdec; + ffmpegdec->picture = av_frame_alloc (); GST_OBJECT_UNLOCK (ffmpegdec); return TRUE; @@ -2328,7 +2319,8 @@ gst_ffmpegviddec_stop (GstVideoDecoder * decoder) GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder); GST_OBJECT_LOCK (ffmpegdec); - gst_ffmpegviddec_close (ffmpegdec, FALSE); + av_frame_free (&ffmpegdec->picture); + gst_ffmpegviddec_close (ffmpegdec); GST_OBJECT_UNLOCK (ffmpegdec); g_free (ffmpegdec->padded); ffmpegdec->padded = NULL; @@ -2382,7 +2374,7 @@ gst_ffmpegviddec_flush (GstVideoDecoder * decoder) { GstFFMpegVidDec *ffmpegdec = GST_FFMPEGVIDDEC (decoder); - if (ffmpegdec->opened) { + if (ffmpegdec->context) { GST_LOG_OBJECT (decoder, "flushing buffers"); GST_VIDEO_DECODER_STREAM_UNLOCK (ffmpegdec); avcodec_flush_buffers (ffmpegdec->context); @@ -2571,11 +2563,10 @@ gst_ffmpegviddec_set_property (GObject * object, switch (prop_id) { case PROP_LOWRES: - ffmpegdec->lowres = ffmpegdec->context->lowres = g_value_get_enum (value); + ffmpegdec->lowres = g_value_get_enum (value); break; case PROP_SKIPFRAME: - ffmpegdec->skip_frame = ffmpegdec->context->skip_frame = - g_value_get_enum (value); + ffmpegdec->skip_frame = g_value_get_enum (value); break; case PROP_DIRECT_RENDERING: ffmpegdec->direct_rendering = g_value_get_boolean (value); diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.h b/subprojects/gst-libav/ext/libav/gstavviddec.h index 0f713de569..14d5a9aff3 100644 --- a/subprojects/gst-libav/ext/libav/gstavviddec.h +++ b/subprojects/gst-libav/ext/libav/gstavviddec.h @@ -54,7 +54,6 @@ struct _GstFFMpegVidDec GstVideoMultiviewMode picture_multiview_mode; GstVideoMultiviewFlags picture_multiview_flags; gint stride[AV_NUM_DATA_POINTERS]; - gboolean opened; /* current output pictures */ enum AVPixelFormat pic_pix_fmt; diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.c b/subprojects/gst-libav/ext/libav/gstavvidenc.c index 461263b4f6..78694c303f 100644 --- a/subprojects/gst-libav/ext/libav/gstavvidenc.c +++ b/subprojects/gst-libav/ext/libav/gstavvidenc.c @@ -208,10 +208,7 @@ gst_ffmpegvidenc_init (GstFFMpegVidEnc * ffmpegenc) GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_ENCODER_SINK_PAD (ffmpegenc)); - ffmpegenc->context = avcodec_alloc_context3 (klass->in_plugin); ffmpegenc->refcontext = avcodec_alloc_context3 (klass->in_plugin); - ffmpegenc->picture = av_frame_alloc (); - ffmpegenc->opened = FALSE; ffmpegenc->file = NULL; } @@ -222,10 +219,8 @@ gst_ffmpegvidenc_finalize (GObject * object) /* clean up remaining allocated data */ av_frame_free (&ffmpegenc->picture); - gst_ffmpeg_avcodec_close (ffmpegenc->context); - gst_ffmpeg_avcodec_close (ffmpegenc->refcontext); - av_freep (&ffmpegenc->context); - av_freep (&ffmpegenc->refcontext); + avcodec_free_context (&ffmpegenc->context); + avcodec_free_context (&ffmpegenc->refcontext); g_free (ffmpegenc->filename); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -247,14 +242,11 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder, ffmpegenc->need_reopen = FALSE; /* close old session */ - if (ffmpegenc->opened) { - avcodec_free_context (&ffmpegenc->context); - ffmpegenc->opened = FALSE; - ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegenc->context == NULL) { - GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); - return FALSE; - } + avcodec_free_context (&ffmpegenc->context); + ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin); + if (ffmpegenc->context == NULL) { + GST_DEBUG_OBJECT (ffmpegenc, "Failed to allocate context"); + return FALSE; } /* additional avcodec settings */ @@ -402,7 +394,6 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder, /* success! */ ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE; - ffmpegenc->opened = TRUE; return TRUE; @@ -412,6 +403,7 @@ open_file_err: GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, OPEN_WRITE, (("Could not open file \"%s\" for writing."), ffmpegenc->filename), GST_ERROR_SYSTEM); + avcodec_free_context (&ffmpegenc->context); return FALSE; } file_read_err: @@ -419,6 +411,7 @@ file_read_err: GST_ELEMENT_ERROR (ffmpegenc, RESOURCE, READ, (("Could not get contents of file \"%s\"."), ffmpegenc->filename), GST_ERROR_SYSTEM); + avcodec_free_context (&ffmpegenc->context); return FALSE; } @@ -426,12 +419,12 @@ 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; + goto close_codec; } unsupported_codec: { GST_DEBUG ("Unsupported codec - no caps found"); - goto cleanup_stats_in; + goto close_codec; } open_codec_fail: { @@ -456,15 +449,13 @@ bad_input_fmt: } close_codec: { + if (ffmpegenc->context) + g_free (ffmpegenc->context->stats_in); + if (ffmpegenc->file) { + fclose (ffmpegenc->file); + ffmpegenc->file = NULL; + } avcodec_free_context (&ffmpegenc->context); - ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegenc->context == NULL) - GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); - goto cleanup_stats_in; - } -cleanup_stats_in: - { - g_free (ffmpegenc->context->stats_in); return FALSE; } } @@ -483,8 +474,7 @@ gst_ffmpegvidenc_propose_allocation (GstVideoEncoder * encoder, static void gst_ffmpegvidenc_free_avpacket (gpointer pkt) { - av_packet_unref ((AVPacket *) pkt); - g_free (pkt); + av_packet_free ((AVPacket **) & pkt); } typedef struct @@ -692,18 +682,18 @@ gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc, *got_packet = FALSE; - pkt = g_new0 (AVPacket, 1); - + pkt = av_packet_alloc (); res = avcodec_receive_packet (ffmpegenc->context, pkt); if (res == AVERROR (EAGAIN)) { - g_free (pkt); + av_packet_free (&pkt); goto done; } else if (res == AVERROR_EOF) { - g_free (pkt); + av_packet_free (&pkt); ret = GST_FLOW_EOS; goto done; } else if (res < 0) { + av_packet_free (&pkt); ret = GST_FLOW_ERROR; goto done; } @@ -767,7 +757,7 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder, GstFlowReturn ret; gboolean got_packet; - /* endoder was drained or flushed, and ffmpeg encoder doesn't support + /* encoder was drained or flushed, and ffmpeg encoder doesn't support * flushing. We need to re-open encoder then */ if (ffmpegenc->need_reopen) { gboolean reopen_ret; @@ -778,6 +768,7 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder, if (!ffmpegenc->input_state) { GST_ERROR_OBJECT (ffmpegenc, "Cannot re-open encoder without input state"); + gst_video_codec_frame_unref (frame); return GST_FLOW_NOT_NEGOTIATED; } @@ -787,6 +778,7 @@ gst_ffmpegvidenc_handle_frame (GstVideoEncoder * encoder, if (!reopen_ret) { GST_ERROR_OBJECT (ffmpegenc, "Couldn't re-open encoder"); + gst_video_codec_frame_unref (frame); return GST_FLOW_NOT_NEGOTIATED; } } @@ -831,7 +823,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send) GST_DEBUG_OBJECT (ffmpegenc, "flushing buffers with sending %d", send); /* no need to empty codec if there is none */ - if (!ffmpegenc->opened) + if (!ffmpegenc->context) goto done; ret = gst_ffmpegvidenc_send_frame (ffmpegenc, NULL); @@ -867,7 +859,7 @@ gst_ffmpegvidenc_set_property (GObject * object, ffmpegenc = (GstFFMpegVidEnc *) (object); - if (ffmpegenc->opened) { + if (ffmpegenc->context) { GST_WARNING_OBJECT (ffmpegenc, "Can't change properties once decoder is setup !"); return; @@ -921,7 +913,7 @@ gst_ffmpegvidenc_flush (GstVideoEncoder * encoder) { GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; - if (ffmpegenc->opened) { + if (ffmpegenc->context) { avcodec_flush_buffers (ffmpegenc->context); ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE; } @@ -933,20 +925,19 @@ static gboolean gst_ffmpegvidenc_start (GstVideoEncoder * encoder) { GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; - GstFFMpegVidEncClass *oclass = - (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); - - ffmpegenc->opened = FALSE; - ffmpegenc->need_reopen = FALSE; /* close old session */ - avcodec_free_context (&ffmpegenc->context); - ffmpegenc->context = avcodec_alloc_context3 (oclass->in_plugin); - if (ffmpegenc->context == NULL) { - GST_DEBUG_OBJECT (ffmpegenc, "Failed to set context defaults"); - return FALSE; + if (ffmpegenc->file) { + fclose (ffmpegenc->file); + ffmpegenc->file = NULL; } + if (ffmpegenc->context) + g_free (ffmpegenc->context->stats_in); + avcodec_free_context (&ffmpegenc->context); + av_frame_free (&ffmpegenc->picture); + ffmpegenc->need_reopen = FALSE; + ffmpegenc->picture = av_frame_alloc (); gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000); return TRUE; @@ -958,8 +949,14 @@ gst_ffmpegvidenc_stop (GstVideoEncoder * encoder) GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder; gst_ffmpegvidenc_flush_buffers (ffmpegenc, FALSE); - gst_ffmpeg_avcodec_close (ffmpegenc->context); - ffmpegenc->opened = FALSE; + if (ffmpegenc->context) + g_free (ffmpegenc->context->stats_in); + if (ffmpegenc->file) { + fclose (ffmpegenc->file); + ffmpegenc->file = NULL; + } + avcodec_free_context (&ffmpegenc->context); + av_frame_free (&ffmpegenc->picture); ffmpegenc->need_reopen = FALSE; if (ffmpegenc->input_state) { diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.h b/subprojects/gst-libav/ext/libav/gstavvidenc.h index 340fb25204..1e73c9ac57 100644 --- a/subprojects/gst-libav/ext/libav/gstavvidenc.h +++ b/subprojects/gst-libav/ext/libav/gstavvidenc.h @@ -41,7 +41,6 @@ struct _GstFFMpegVidEnc AVCodecContext *context; AVFrame *picture; GstClockTime pts_offset; - gboolean opened; gboolean need_reopen; gboolean discont; guint pass;