From 6984879ed68d6edefb012ff5fd980168a314155c Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Fri, 5 Aug 2005 15:29:56 +0000 Subject: [PATCH] Backport BRANCH-THREADED to HEAD, fix a bit. Original commit message from CVS: * configure.ac: * ext/ffmpeg/Makefile.am: * ext/ffmpeg/gstffmpeg.c: (plugin_init): * ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_caps_with_codecid): * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_class_init), (gst_ffmpegdec_init), (gst_ffmpegdec_query), (gst_ffmpegdec_event), (gst_ffmpegdec_open), (gst_ffmpegdec_setcaps), (gst_ffmpegdec_get_buffer), (gst_ffmpegdec_negotiate), (gst_ffmpegdec_frame), (gst_ffmpegdec_sink_event), (gst_ffmpegdec_chain), (gst_ffmpegdec_change_state), (gst_ffmpegdec_register): * ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_class_init), (gst_ffmpegenc_init), (gst_ffmpegenc_getcaps), (gst_ffmpegenc_setcaps), (gst_ffmpegenc_chain_video), (gst_ffmpegenc_chain_audio): * ext/libpostproc/Makefile.am: Backport BRANCH-THREADED to HEAD, fix a bit. --- ChangeLog | 22 ++++ configure.ac | 8 +- ext/ffmpeg/Makefile.am | 15 ++- ext/ffmpeg/gstffmpeg.c | 5 +- ext/ffmpeg/gstffmpegcodecmap.c | 2 +- ext/ffmpeg/gstffmpegdec.c | 276 ++++++++++++++++++++++++----------------- ext/ffmpeg/gstffmpegenc.c | 94 +++++++------- ext/libpostproc/Makefile.am | 31 +++-- 8 files changed, 258 insertions(+), 195 deletions(-) diff --git a/ChangeLog b/ChangeLog index bba2ae1..79138d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,27 @@ 2005-08-05 Ronald S. Bultje + * configure.ac: + * ext/ffmpeg/Makefile.am: + * ext/ffmpeg/gstffmpeg.c: (plugin_init): + * ext/ffmpeg/gstffmpegcodecmap.c: (gst_ffmpeg_caps_with_codecid): + * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_class_init), + (gst_ffmpegdec_init), (gst_ffmpegdec_query), (gst_ffmpegdec_event), + (gst_ffmpegdec_open), (gst_ffmpegdec_setcaps), + (gst_ffmpegdec_get_buffer), (gst_ffmpegdec_negotiate), + (gst_ffmpegdec_frame), (gst_ffmpegdec_sink_event), + (gst_ffmpegdec_chain), (gst_ffmpegdec_change_state), + (gst_ffmpegdec_register): + * ext/ffmpeg/gstffmpegenc.c: (gst_ffmpegenc_class_init), + (gst_ffmpegenc_init), (gst_ffmpegenc_getcaps), + (gst_ffmpegenc_setcaps), (gst_ffmpegenc_chain_video), + (gst_ffmpegenc_chain_audio): + * ext/libpostproc/Makefile.am: + Backport BRANCH-THREADED to HEAD, fix a bit. + +=== release 0.8.6 === + +2005-08-05 Ronald S. Bultje + * NEWS: * RELEASE: * configure.ac: diff --git a/configure.ac b/configure.ac index 5c3f4e7..84a77ba 100644 --- a/configure.ac +++ b/configure.ac @@ -12,19 +12,19 @@ AM_MAINTAINER_MODE dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AS_VERSION(gst-ffmpeg, GST_FFMPEG_VERSION, 0, 8, 6, 0, GST_CVS="no", GST_CVS="yes") +AS_VERSION(gst-ffmpeg, GST_FFMPEG_VERSION, 0, 9, 0, 1, GST_CVS="no", GST_CVS="yes") dnl we cheat here so we don't have to change the actual configure code bit GST_PLUGINS_VERSION_NANO=$GST_FFMPEG_VERSION_NANO dnl required GStreamer version -GST_REQ=0.8.4 +GST_REQ=0.9.1 AM_INIT_AUTOMAKE($PACKAGE,$VERSION) dnl our libraries and install dirs use major.minor as a version #GST_MAJORMINOR=$GST_FFMPEG_VERSION_MAJOR.$GST_FFMPEG_VERSION_MINOR dnl hack while GST_MAJORMINOR doesn't match the release -GST_MAJORMINOR=0.8 +GST_MAJORMINOR=0.9 AC_SUBST(GST_MAJORMINOR) dnl CURRENT, REVISION, AGE @@ -62,7 +62,7 @@ AC_HEADER_STDC([]) dnl check for gstreamer; uninstalled is selected preferentially -- see pkg-config(1) PKG_CHECK_MODULES(GST, gstreamer-$GST_MAJORMINOR >= $GST_REQ \ - gstreamer-libs-$GST_MAJORMINOR, + gstreamer-plugins-base-$GST_MAJORMINOR, HAVE_GST="yes", HAVE_GST="no") if test "x$HAVE_GST" = "xno"; then diff --git a/ext/ffmpeg/Makefile.am b/ext/ffmpeg/Makefile.am index b2eb1ab..0068308 100644 --- a/ext/ffmpeg/Makefile.am +++ b/ext/ffmpeg/Makefile.am @@ -1,16 +1,15 @@ - plugin_LTLIBRARIES = libgstffmpeg.la libgstffmpeg_la_SOURCES = gstffmpeg.c \ gstffmpegcodecmap.c \ gstffmpegdec.c \ - gstffmpegdemux.c \ - gstffmpegenc.c \ - gstffmpegmux.c \ - gstffmpegprotocol.c \ - gstffmpegcolorspace.c \ - gstffmpegscale.c \ - gstffmpegdeinterlace.c + gstffmpegenc.c +# gstffmpegdemux.c \ +# gstffmpegmux.c \ +# gstffmpegprotocol.c \ +# gstffmpegcolorspace.c \ +# gstffmpegscale.c \ +# gstffmpegdeinterlace.c libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) \ -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \ diff --git a/ext/ffmpeg/gstffmpeg.c b/ext/ffmpeg/gstffmpeg.c index d9d2e30..70f3f1d 100644 --- a/ext/ffmpeg/gstffmpeg.c +++ b/ext/ffmpeg/gstffmpeg.c @@ -68,9 +68,6 @@ gst_ffmpeg_log_callback (void * ptr, int level, const char * fmt, va_list vl) static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_library_load ("gstbytestream")) - return FALSE; - GST_DEBUG_CATEGORY_INIT (ffmpeg_debug, "ffmpeg", 0, "FFmpeg elements"); #ifndef GST_DISABLE_GST_DEBUG av_log_set_callback (gst_ffmpeg_log_callback); @@ -79,6 +76,7 @@ plugin_init (GstPlugin * plugin) gst_ffmpegenc_register (plugin); gst_ffmpegdec_register (plugin); +#if 0 gst_ffmpegdemux_register (plugin); gst_ffmpegmux_register (plugin); gst_ffmpegcsp_register (plugin); @@ -86,6 +84,7 @@ plugin_init (GstPlugin * plugin) gst_ffmpegdeinterlace_register (plugin); register_protocol (&gstreamer_protocol); +#endif /* Now we can return the pointer to the newly created Plugin object. */ return TRUE; diff --git a/ext/ffmpeg/gstffmpegcodecmap.c b/ext/ffmpeg/gstffmpegcodecmap.c index c59c6ed..78b5f49 100644 --- a/ext/ffmpeg/gstffmpegcodecmap.c +++ b/ext/ffmpeg/gstffmpegcodecmap.c @@ -1226,7 +1226,7 @@ gst_ffmpeg_caps_with_codecid (enum CodecID codec_id, /* extradata parsing (esds [mpeg4], wma/wmv, msmpeg4v1/2/3, etc.) */ if ((value = gst_structure_get_value (str, "codec_data"))) { - buf = g_value_get_boxed (value); + buf = GST_BUFFER (gst_value_get_mini_object (value)); context->extradata = av_mallocz (GST_BUFFER_SIZE (buf)); memcpy (context->extradata, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index 0753b20..bff2b67 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -61,7 +61,7 @@ struct _GstFFMpegDec } audio; } format; gboolean waiting_for_key; - guint64 next_ts; + guint64 next_ts, synctime; /* parsing */ AVCodecParserContext *pctx; @@ -118,13 +118,12 @@ static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass); static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec); static void gst_ffmpegdec_dispose (GObject * object); -static gboolean gst_ffmpegdec_query (GstPad * pad, GstQueryType type, - GstFormat * fmt, gint64 * value); +static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery *query); static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event); -static GstPadLinkReturn gst_ffmpegdec_connect (GstPad * pad, - const GstCaps * caps); -static void gst_ffmpegdec_chain (GstPad * pad, GstData * data); +static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf); static GstElementStateReturn gst_ffmpegdec_change_state (GstElement * element); @@ -237,6 +236,11 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) parent_class = g_type_class_peek_parent (klass); + gobject_class->dispose = gst_ffmpegdec_dispose; + gobject_class->set_property = gst_ffmpegdec_set_property; + gobject_class->get_property = gst_ffmpegdec_get_property; + gstelement_class->change_state = gst_ffmpegdec_change_state; + g_object_class_install_property (gobject_class, ARG_SKIPFRAME, g_param_spec_enum ("skip-frame", "Skip frames", "Which types of frames to skip during decoding", @@ -245,11 +249,6 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) g_param_spec_enum ("lowres", "Low resolution", "At which resolution to decode images", GST_FFMPEGDEC_TYPE_LOWRES, 0, G_PARAM_READWRITE)); - - gobject_class->dispose = gst_ffmpegdec_dispose; - gobject_class->set_property = gst_ffmpegdec_set_property; - gobject_class->get_property = gst_ffmpegdec_get_property; - gstelement_class->change_state = gst_ffmpegdec_change_state; } static void @@ -260,12 +259,13 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) /* setup pads */ ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); - gst_pad_set_link_function (ffmpegdec->sinkpad, gst_ffmpegdec_connect); + gst_pad_set_setcaps_function (ffmpegdec->sinkpad, gst_ffmpegdec_setcaps); + gst_pad_set_event_function (ffmpegdec->sinkpad, gst_ffmpegdec_sink_event); gst_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad); ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); - gst_pad_use_explicit_caps (ffmpegdec->srcpad); + gst_pad_use_fixed_caps (ffmpegdec->srcpad); gst_pad_set_event_function (ffmpegdec->srcpad, GST_DEBUG_FUNCPTR (gst_ffmpegdec_event)); gst_pad_set_query_function (ffmpegdec->srcpad, @@ -283,8 +283,6 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) ffmpegdec->hurry_up = ffmpegdec->lowres = 0; ffmpegdec->last_buffer = NULL; - - GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE); } static void @@ -302,19 +300,24 @@ gst_ffmpegdec_dispose (GObject * object) } static gboolean -gst_ffmpegdec_query (GstPad * pad, GstQueryType type, - GstFormat * fmt, gint64 * value) +gst_ffmpegdec_query (GstPad * pad, GstQuery *query) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); - GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad); - GstFormat bfmt = GST_FORMAT_BYTES; + GstFFMpegDec *ffmpegdec; + GstPad *peer; + GstFormat bfmt; + + bfmt = GST_FORMAT_BYTES; + ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad); + peer = GST_PAD_PEER (ffmpegdec->sinkpad); if (!peer) - return FALSE; + goto no_peer; - if (gst_pad_query (peer, type, fmt, value)) + /* just forward to peer */ + if (gst_pad_query (peer, query)) return TRUE; +#if 0 /* ok, do bitrate calc... */ if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) || *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 || @@ -324,19 +327,28 @@ gst_ffmpegdec_query (GstPad * pad, GstQueryType type, if (ffmpegdec->pcache && type == GST_QUERY_POSITION) *value -= GST_BUFFER_SIZE (ffmpegdec->pcache); *value *= GST_SECOND / ffmpegdec->context->bit_rate; +#endif - return TRUE; + return FALSE; + +no_peer: + { + return FALSE; + } } static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); - GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad); + GstFFMpegDec *ffmpegdec; + GstPad *peer; + + ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad); + peer = GST_PAD_PEER (ffmpegdec->sinkpad); if (!peer) return FALSE; - + gst_event_ref (event); if (gst_pad_send_event (peer, event)) { gst_event_unref (event); @@ -389,13 +401,10 @@ gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec) GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) + goto could_not_open; + ffmpegdec->opened = TRUE; - if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) { - gst_ffmpegdec_close (ffmpegdec); - GST_DEBUG ("ffdec_%s: Failed to open FFMPEG codec", - oclass->in_plugin->name); - return FALSE; - } GST_LOG ("Opened ffmpeg codec %s", oclass->in_plugin->name); @@ -425,16 +434,25 @@ gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec) break; } ffmpegdec->next_ts = 0; - + ffmpegdec->synctime = GST_CLOCK_TIME_NONE; ffmpegdec->last_buffer = NULL; return TRUE; + + /* ERRORS */ +could_not_open: + { + gst_ffmpegdec_close (ffmpegdec); + GST_DEBUG ("ffdec_%s: Failed to open FFMPEG codec", + oclass->in_plugin->name); + return FALSE; + } } static GstPadLinkReturn -gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps) +gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) { - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad)); + GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_OBJECT_PARENT (pad)); GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GstStructure *structure; @@ -485,10 +503,10 @@ gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps) g_free (ffmpegdec->par); ffmpegdec->par = NULL; } - return GST_PAD_LINK_REFUSED; + return FALSE; } - return GST_PAD_LINK_OK; + return TRUE; } static int @@ -528,7 +546,8 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) return avcodec_default_get_buffer(context, picture); } - buf = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, bufsize); + if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, bufsize, GST_PAD_CAPS (ffmpegdec->srcpad), &buf) != GST_FLOW_OK) + return -1; ffmpegdec->last_buffer = buf; gst_ffmpeg_avpicture_fill ((AVPicture *) picture, @@ -647,18 +666,18 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec) } if (caps == NULL || - !gst_pad_set_explicit_caps (ffmpegdec->srcpad, caps)) { + !gst_pad_set_caps (ffmpegdec->srcpad, caps)) { GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("Failed to link ffmpeg decoder (%s) to next element", oclass->in_plugin->name)); if (caps != NULL) - gst_caps_free (caps); + gst_caps_unref (caps); return FALSE; } - gst_caps_free (caps); + gst_caps_unref (caps); return TRUE; } @@ -671,7 +690,8 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); GstBuffer *outbuf = NULL; gint have_data = 0, len = 0; - + GstFlowReturn ret; + ffmpegdec->context->frame_number++; switch (oclass->in_plugin->type) { @@ -685,6 +705,43 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, GST_DEBUG_OBJECT (ffmpegdec, "Decode video: len=%d, have_data=%d", len, have_data); + if (ffmpegdec->waiting_for_key) { + if (ffmpegdec->picture->pict_type == FF_I_TYPE) { + ffmpegdec->waiting_for_key = FALSE; + } else { + GST_WARNING_OBJECT (ffmpegdec, + "Dropping non-keyframe (seek/init)"); + have_data = 0; + break; + } + } + + /* note that ffmpeg sometimes gets the FPS wrong. + * For B-frame containing movies, we get all pictures delayed + * except for the I frames, so we synchronize only on I frames + * and keep an internal counter based on FPS for the others. */ + if (!(oclass->in_plugin->capabilities & CODEC_CAP_DELAY) || + ((ffmpegdec->picture->pict_type == FF_I_TYPE || + !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) && + GST_CLOCK_TIME_IS_VALID (*in_ts))) { + ffmpegdec->next_ts = *in_ts; + *in_ts = GST_CLOCK_TIME_NONE; + } + + /* precise seeking.... */ + if (GST_CLOCK_TIME_IS_VALID (ffmpegdec->synctime)) { + if (ffmpegdec->next_ts >= ffmpegdec->synctime) { + ffmpegdec->synctime = GST_CLOCK_TIME_NONE; + } else { + GST_WARNING_OBJECT (ffmpegdec, + "Dropping frame for synctime %" GST_TIME_FORMAT ", expected %" + GST_TIME_FORMAT, GST_TIME_ARGS (ffmpegdec->synctime), + GST_TIME_ARGS (ffmpegdec->next_ts)); + have_data = 0; + /* don´t break here! Timestamps are updated below */ + } + } + if (ffmpegdec->waiting_for_key && ffmpegdec->picture->pict_type != FF_I_TYPE) { have_data = 0; @@ -705,7 +762,8 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, if (!gst_ffmpegdec_negotiate (ffmpegdec)) return -1; - outbuf = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize); + if ((ret = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize, GST_PAD_CAPS (ffmpegdec->srcpad), &outbuf)) != GST_FLOW_OK) + return ret; /* original ffmpeg code does not handle odd sizes correctly. * This patched up version does */ @@ -725,22 +783,8 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, ffmpegdec->waiting_for_key = FALSE; - /* note that ffmpeg sometimes gets the FPS wrong. - * For B-frame containing movies, we get all pictures delayed - * except for the I frames, so we synchronize only on I frames - * and keep an internal counter based on FPS for the others. */ - if (!(oclass->in_plugin->capabilities & CODEC_CAP_DELAY) || - ((ffmpegdec->picture->pict_type == FF_I_TYPE || - !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) && - GST_CLOCK_TIME_IS_VALID (*in_ts))) { - ffmpegdec->next_ts = *in_ts; - *in_ts = GST_CLOCK_TIME_NONE; - } - - if (ffmpegdec->picture->key_frame) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT); - } else { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DELTA_UNIT); + if (!ffmpegdec->picture->key_frame) { + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); } GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts; @@ -753,7 +797,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, /* Take repeat_pict into account */ GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf) * ffmpegdec->picture->repeat_pict / 2; - + ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf); } else { ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; @@ -776,7 +820,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, /* Take repeat_pict into account */ dur += dur * ffmpegdec->picture->repeat_pict / 2; - + ffmpegdec->next_ts += dur; } else { ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; @@ -840,22 +884,20 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, } if (have_data) { - GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%" GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); - if (GST_PAD_IS_USABLE (ffmpegdec->srcpad)) - gst_pad_push (ffmpegdec->srcpad, GST_DATA (outbuf)); - else - gst_buffer_unref (outbuf); + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad)); + gst_pad_push (ffmpegdec->srcpad, outbuf); } return len; } -static void -gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event) +static gboolean +gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) { + GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad); GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); @@ -874,30 +916,31 @@ gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event) } while (try++ < 10); } goto forward; - case GST_EVENT_FLUSH: + case GST_EVENT_FLUSH_START: if (ffmpegdec->opened) { avcodec_flush_buffers (ffmpegdec->context); } goto forward; - case GST_EVENT_DISCONTINUOUS: { - gint64 value; - - if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { - ffmpegdec->next_ts = value; + case GST_EVENT_NEWSEGMENT: { + gint64 base, start, end; + gdouble rate; + GstFormat fmt; + + gst_event_parse_newsegment (event, &rate, &fmt, &start, &end, &base); + if (fmt == GST_FORMAT_TIME) { + ffmpegdec->next_ts = start; GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT, - GST_TIME_ARGS (value)); - } else if (ffmpegdec->context->bit_rate && - gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) { - gboolean new_media; - - ffmpegdec->next_ts = value * GST_SECOND / ffmpegdec->context->bit_rate; + GST_TIME_ARGS (start)); + } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) { + ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate; GST_DEBUG_OBJECT (ffmpegdec, "Discont to byte %lld, time %" GST_TIME_FORMAT, - value, GST_TIME_ARGS (ffmpegdec->next_ts)); - new_media = GST_EVENT_DISCONT_NEW_MEDIA (event); + start, GST_TIME_ARGS (ffmpegdec->next_ts)); gst_event_unref (event); - event = gst_event_new_discontinuous (new_media, - GST_FORMAT_TIME, ffmpegdec->next_ts, GST_FORMAT_UNDEFINED); + event = gst_event_new_newsegment (rate, fmt, + start * GST_SECOND / ffmpegdec->context->bit_rate, + end * GST_SECOND / ffmpegdec->context->bit_rate, + base * GST_SECOND / ffmpegdec->context->bit_rate); } else { GST_WARNING_OBJECT (ffmpegdec, "Received discont with no useful value..."); @@ -911,49 +954,39 @@ gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event) ffmpegdec->waiting_for_key = TRUE; } } + ffmpegdec->waiting_for_key = TRUE; + ffmpegdec->synctime = ffmpegdec->next_ts; /* fall-through */ } default: forward: - gst_pad_event_default (ffmpegdec->sinkpad, event); - return; + return gst_pad_event_default (ffmpegdec->sinkpad, event); } + + return TRUE; } -static void -gst_ffmpegdec_chain (GstPad * pad, GstData * _data) +static GstFlowReturn +gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) { - GstBuffer *inbuf; - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad)); + GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad)); GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); guint8 *bdata, *data; gint bsize, size, len, have_data; - guint64 in_ts; - - /* event handling */ - if (GST_IS_EVENT (_data)) { - gst_ffmpegdec_handle_event (ffmpegdec, GST_EVENT (_data)); - return; - } - - inbuf = GST_BUFFER (_data); - in_ts = GST_BUFFER_TIMESTAMP (inbuf); - - if (!ffmpegdec->opened) { - GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), - ("ffdec_%s: input format was not set before data start", - oclass->in_plugin->name)); - return; - } + guint64 in_ts = GST_BUFFER_TIMESTAMP (inbuf); + if (!ffmpegdec->opened) + goto not_negotiated; + GST_DEBUG_OBJECT (ffmpegdec, "Received new data of size %d, time %" GST_TIME_FORMAT, GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf))); /* parse cache joining */ if (ffmpegdec->pcache) { - inbuf = gst_buffer_join (ffmpegdec->pcache, inbuf); + inbuf = gst_buffer_span (ffmpegdec->pcache, 0, inbuf, + GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf)); ffmpegdec->pcache = NULL; bdata = GST_BUFFER_DATA (inbuf); bsize = GST_BUFFER_SIZE (inbuf); @@ -964,7 +997,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstData * _data) * ffmpeg devs know about it and will fix it (they said). */ else if (oclass->in_plugin->id == CODEC_ID_SVQ1 || oclass->in_plugin->id == CODEC_ID_SVQ3) { - inbuf = gst_buffer_copy_on_write (inbuf); + inbuf = gst_buffer_make_writable (inbuf); bdata = GST_BUFFER_DATA (inbuf); bsize = GST_BUFFER_SIZE (inbuf); } else { @@ -1023,6 +1056,17 @@ gst_ffmpegdec_chain (GstPad * pad, GstData * _data) GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize); } gst_buffer_unref (inbuf); + + return GST_FLOW_OK; + + /* ERRORS */ +not_negotiated: + { + GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), + ("ffdec_%s: input format was not set before data start", + oclass->in_plugin->name)); + return GST_FLOW_NOT_NEGOTIATED; + } } static GstElementStateReturn @@ -1030,6 +1074,9 @@ gst_ffmpegdec_change_state (GstElement * element) { GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element; gint transition = GST_STATE_TRANSITION (element); + GstElementStateReturn ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); switch (transition) { case GST_STATE_PAUSED_TO_READY: @@ -1039,12 +1086,11 @@ gst_ffmpegdec_change_state (GstElement * element) ffmpegdec->last_buffer = NULL; } break; + default: + break; } - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element); - - return GST_STATE_SUCCESS; + return ret; } static void @@ -1141,8 +1187,8 @@ gst_ffmpegdec_register (GstPlugin * plugin) srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL); } if (!sinkcaps || !srccaps) { - if (sinkcaps) gst_caps_free (sinkcaps); - if (srccaps) gst_caps_free (srccaps); + if (sinkcaps) gst_caps_unref (sinkcaps); + if (srccaps) gst_caps_unref (srccaps); goto next; } diff --git a/ext/ffmpeg/gstffmpegenc.c b/ext/ffmpeg/gstffmpegenc.c index ca859f2..bad5157 100644 --- a/ext/ffmpeg/gstffmpegenc.c +++ b/ext/ffmpeg/gstffmpegenc.c @@ -132,11 +132,10 @@ static void gst_ffmpegenc_base_init (GstFFMpegEncClass * klass); static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc); static void gst_ffmpegenc_dispose (GObject * object); -static GstPadLinkReturn gst_ffmpegenc_link (GstPad * pad, - const GstCaps * caps); +static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps); static GstCaps * gst_ffmpegenc_getcaps (GstPad * pad); -static void gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data); -static void gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data); +static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer *buffer); +static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer *buffer); static void gst_ffmpegenc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -206,6 +205,9 @@ gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + gobject_class->set_property = gst_ffmpegenc_set_property; + gobject_class->get_property = gst_ffmpegenc_get_property; + if (klass->in_plugin->type == CODEC_TYPE_VIDEO) { g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, g_param_spec_ulong ("bitrate", "Bit Rate", @@ -227,9 +229,6 @@ gst_ffmpegenc_class_init (GstFFMpegEncClass * klass) "Target Audio Bitrate", 0, G_MAXULONG, 128000, G_PARAM_READWRITE)); } - gobject_class->set_property = gst_ffmpegenc_set_property; - gobject_class->get_property = gst_ffmpegenc_get_property; - gstelement_class->change_state = gst_ffmpegenc_change_state; gobject_class->dispose = gst_ffmpegenc_dispose; @@ -243,10 +242,10 @@ gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc) /* setup pads */ ffmpegenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); - gst_pad_set_link_function (ffmpegenc->sinkpad, gst_ffmpegenc_link); + gst_pad_set_setcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_setcaps); gst_pad_set_getcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_getcaps); ffmpegenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); - gst_pad_use_explicit_caps (ffmpegenc->srcpad); + gst_pad_use_fixed_caps (ffmpegenc->srcpad); /* ffmpeg objects */ ffmpegenc->context = avcodec_alloc_context (); @@ -290,7 +289,7 @@ gst_ffmpegenc_dispose (GObject * object) static GstCaps * gst_ffmpegenc_getcaps (GstPad * pad) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) gst_pad_get_parent (pad); + GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); GstFFMpegEncClass *oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); AVCodecContext *ctx; @@ -348,14 +347,14 @@ gst_ffmpegenc_getcaps (GstPad * pad) return caps; } -static GstPadLinkReturn -gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps) +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_get_parent (pad); + GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad); GstFFMpegEncClass *oclass = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); @@ -425,10 +424,10 @@ gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps) } icaps = gst_caps_intersect (allowed_caps, other_caps); - gst_caps_free (allowed_caps); - gst_caps_free (other_caps); + gst_caps_unref (allowed_caps); + gst_caps_unref (other_caps); if (gst_caps_is_empty (icaps)) { - gst_caps_free (icaps); + gst_caps_unref (icaps); return GST_PAD_LINK_REFUSED; } @@ -438,18 +437,16 @@ gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps) newcaps = gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps, 0)), NULL); - gst_caps_free (icaps); + gst_caps_unref (icaps); icaps = newcaps; } - /* FIXME set_explicit_caps is not supposed to be used in a pad link - * function. */ - if (!gst_pad_set_explicit_caps (ffmpegenc->srcpad, icaps)) { + if (!gst_pad_set_caps (ffmpegenc->srcpad, icaps)) { avcodec_close (ffmpegenc->context); - gst_caps_free (icaps); + gst_caps_unref (icaps); return GST_PAD_LINK_REFUSED; } - gst_caps_free (icaps); + gst_caps_unref (icaps); /* success! */ ffmpegenc->opened = TRUE; @@ -457,15 +454,14 @@ gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps) return GST_PAD_LINK_OK; } -static void -gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data) +static GstFlowReturn +gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf) { - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (gst_pad_get_parent (pad)); - GstBuffer *inbuf = GST_BUFFER (_data), *outbuf; + GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad)); + GstBuffer *outbuf; GstFFMpegEncClass *oclass = (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); gint ret_size = 0, frame_size; - const AVRational bq = { 1, 1000000000 }; /* FIXME: events (discont (flush!) and eos (close down) etc.) */ @@ -477,7 +473,7 @@ gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data) GST_BUFFER_DATA (inbuf), ffmpegenc->context->pix_fmt, ffmpegenc->context->width, ffmpegenc->context->height); - g_return_if_fail (frame_size == GST_BUFFER_SIZE (inbuf)); + g_return_val_if_fail (frame_size == GST_BUFFER_SIZE (inbuf), GST_FLOW_ERROR); ffmpegenc->picture->pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (inbuf), @@ -486,35 +482,33 @@ gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data) outbuf = gst_buffer_new_and_alloc (ffmpegenc->buffer_size); ret_size = avcodec_encode_video (ffmpegenc->context, GST_BUFFER_DATA (outbuf), - GST_BUFFER_MAXSIZE (outbuf), ffmpegenc->picture); + GST_BUFFER_SIZE (outbuf), ffmpegenc->picture); if (ret_size < 0) { GST_ERROR_OBJECT (ffmpegenc, "ffenc_%s: failed to encode buffer", oclass->in_plugin->name); gst_buffer_unref (inbuf); gst_buffer_unref (outbuf); - return; + return GST_FLOW_OK; } GST_BUFFER_SIZE (outbuf) = ret_size; GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf); - if (ffmpegenc->context->coded_frame->key_frame) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT); - else - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DELTA_UNIT); - gst_pad_push (ffmpegenc->srcpad, GST_DATA (outbuf)); + if (!ffmpegenc->context->coded_frame->key_frame) + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad)); - gst_buffer_unref (inbuf); + return gst_pad_push (ffmpegenc->srcpad, outbuf); } -static void -gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) +static GstFlowReturn +gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf) { - GstBuffer *inbuf = GST_BUFFER (_data); GstBuffer *outbuf = NULL, *subbuf; - GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (gst_pad_get_parent (pad)); + GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_OBJECT_PARENT (pad)); gint size, ret_size = 0, in_size, frame_size; + GstFlowReturn ret; size = GST_BUFFER_SIZE (inbuf); @@ -537,7 +531,8 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) if (in_size > size) { /* this is panic! we got a buffer, but still don't have enough * data. Merge them and retry in the next cycle... */ - ffmpegenc->cache = gst_buffer_merge (ffmpegenc->cache, inbuf); + ffmpegenc->cache = gst_buffer_span (ffmpegenc->cache, 0, inbuf, + GST_BUFFER_SIZE (ffmpegenc->cache) + GST_BUFFER_SIZE (inbuf)); } else if (in_size == size) { /* exactly the same! how wonderful */ ffmpegenc->cache = inbuf; @@ -554,8 +549,7 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) } else { gst_buffer_unref (inbuf); } - - return; + return GST_FLOW_OK; } /* create the frame */ @@ -564,7 +558,8 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) subbuf = gst_buffer_create_sub (inbuf, 0, frame_size - (in_size - size)); GST_BUFFER_DURATION (subbuf) = GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size; - subbuf = gst_buffer_merge (ffmpegenc->cache, subbuf); + subbuf = gst_buffer_span (ffmpegenc->cache, 0, subbuf, + GST_BUFFER_SIZE (ffmpegenc->cache) + GST_BUFFER_SIZE (subbuf)); ffmpegenc->cache = NULL; } else { subbuf = gst_buffer_create_sub (inbuf, size - in_size, frame_size); @@ -578,7 +573,7 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) outbuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (inbuf)); ret_size = avcodec_encode_audio (ffmpegenc->context, GST_BUFFER_DATA (outbuf), - GST_BUFFER_MAXSIZE (outbuf), (const short int *) + GST_BUFFER_SIZE (outbuf), (const short int *) GST_BUFFER_DATA (subbuf)); if (ret_size < 0) { @@ -586,17 +581,20 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) gst_buffer_unref (inbuf); gst_buffer_unref (outbuf); gst_buffer_unref (subbuf); - return; + return GST_FLOW_OK; } GST_BUFFER_SIZE (outbuf) = ret_size; GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (subbuf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (subbuf); - gst_pad_push (ffmpegenc->srcpad, GST_DATA (outbuf)); + gst_buffer_unref (subbuf); + + ret = gst_pad_push (ffmpegenc->srcpad, outbuf); in_size -= frame_size; - gst_buffer_unref (subbuf); } + + return ret; } static void diff --git a/ext/libpostproc/Makefile.am b/ext/libpostproc/Makefile.am index 98577a2..cbb8c60 100644 --- a/ext/libpostproc/Makefile.am +++ b/ext/libpostproc/Makefile.am @@ -1,17 +1,16 @@ - -plugin_LTLIBRARIES = libgstpostproc.la - -libgstpostproc_la_SOURCES = gstpostproc.c - -libgstpostproc_la_CFLAGS = $(GST_CFLAGS) \ - -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \ - -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavcodec -libgstpostproc_la_LIBADD = \ - $(top_builddir)/gst-libs/ext/ffmpeg/libavformat/libavformat.la \ - $(top_builddir)/gst-libs/ext/ffmpeg/libavcodec/libavcodec.la +#plugin_LTLIBRARIES = libgstpostproc.la +# +#libgstpostproc_la_SOURCES = gstpostproc.c +# +#libgstpostproc_la_CFLAGS = $(GST_CFLAGS) \ +# -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \ +# -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavcodec +#libgstpostproc_la_LIBADD = \ +# $(top_builddir)/gst-libs/ext/ffmpeg/libavformat/libavformat.la \ +# $(top_builddir)/gst-libs/ext/ffmpeg/libavcodec/libavcodec.la # $(top_builddir)/gst-libs/ext/ffmpeg/libavcodec/libpostproc/libffpostproc.la - -libgstpostproc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - -noinst_HEADERS = \ - gstpostproc.h \ No newline at end of file +# +#libgstpostproc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +# +#noinst_HEADERS = \ +# gstpostproc.h -- 2.7.4