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.
This commit is contained in:
Ronald S. Bultje 2005-08-05 15:29:56 +00:00
parent 6e4b116b50
commit 6984879ed6
8 changed files with 257 additions and 194 deletions

View file

@ -1,3 +1,25 @@
2005-08-05 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* 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 <rbultje@ronald.bitfreak.net> 2005-08-05 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* NEWS: * NEWS:

View file

@ -12,19 +12,19 @@ AM_MAINTAINER_MODE
dnl when going to/from release please set the nano (fourth number) right ! dnl when going to/from release please set the nano (fourth number) right !
dnl releases only do Wall, cvs and prerelease does Werror too 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 dnl we cheat here so we don't have to change the actual configure code bit
GST_PLUGINS_VERSION_NANO=$GST_FFMPEG_VERSION_NANO GST_PLUGINS_VERSION_NANO=$GST_FFMPEG_VERSION_NANO
dnl required GStreamer version dnl required GStreamer version
GST_REQ=0.8.4 GST_REQ=0.9.1
AM_INIT_AUTOMAKE($PACKAGE,$VERSION) AM_INIT_AUTOMAKE($PACKAGE,$VERSION)
dnl our libraries and install dirs use major.minor as a version dnl our libraries and install dirs use major.minor as a version
#GST_MAJORMINOR=$GST_FFMPEG_VERSION_MAJOR.$GST_FFMPEG_VERSION_MINOR #GST_MAJORMINOR=$GST_FFMPEG_VERSION_MAJOR.$GST_FFMPEG_VERSION_MINOR
dnl hack while GST_MAJORMINOR doesn't match the release dnl hack while GST_MAJORMINOR doesn't match the release
GST_MAJORMINOR=0.8 GST_MAJORMINOR=0.9
AC_SUBST(GST_MAJORMINOR) AC_SUBST(GST_MAJORMINOR)
dnl CURRENT, REVISION, AGE dnl CURRENT, REVISION, AGE
@ -62,7 +62,7 @@ AC_HEADER_STDC([])
dnl check for gstreamer; uninstalled is selected preferentially -- see pkg-config(1) dnl check for gstreamer; uninstalled is selected preferentially -- see pkg-config(1)
PKG_CHECK_MODULES(GST, gstreamer-$GST_MAJORMINOR >= $GST_REQ \ PKG_CHECK_MODULES(GST, gstreamer-$GST_MAJORMINOR >= $GST_REQ \
gstreamer-libs-$GST_MAJORMINOR, gstreamer-plugins-base-$GST_MAJORMINOR,
HAVE_GST="yes", HAVE_GST="no") HAVE_GST="yes", HAVE_GST="no")
if test "x$HAVE_GST" = "xno"; then if test "x$HAVE_GST" = "xno"; then

View file

@ -1,16 +1,15 @@
plugin_LTLIBRARIES = libgstffmpeg.la plugin_LTLIBRARIES = libgstffmpeg.la
libgstffmpeg_la_SOURCES = gstffmpeg.c \ libgstffmpeg_la_SOURCES = gstffmpeg.c \
gstffmpegcodecmap.c \ gstffmpegcodecmap.c \
gstffmpegdec.c \ gstffmpegdec.c \
gstffmpegdemux.c \ gstffmpegenc.c
gstffmpegenc.c \ # gstffmpegdemux.c \
gstffmpegmux.c \ # gstffmpegmux.c \
gstffmpegprotocol.c \ # gstffmpegprotocol.c \
gstffmpegcolorspace.c \ # gstffmpegcolorspace.c \
gstffmpegscale.c \ # gstffmpegscale.c \
gstffmpegdeinterlace.c # gstffmpegdeinterlace.c
libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) \ libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) \
-I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \ -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \

View file

@ -68,9 +68,6 @@ gst_ffmpeg_log_callback (void * ptr, int level, const char * fmt, va_list vl)
static gboolean static gboolean
plugin_init (GstPlugin * plugin) plugin_init (GstPlugin * plugin)
{ {
if (!gst_library_load ("gstbytestream"))
return FALSE;
GST_DEBUG_CATEGORY_INIT (ffmpeg_debug, "ffmpeg", 0, "FFmpeg elements"); GST_DEBUG_CATEGORY_INIT (ffmpeg_debug, "ffmpeg", 0, "FFmpeg elements");
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
av_log_set_callback (gst_ffmpeg_log_callback); av_log_set_callback (gst_ffmpeg_log_callback);
@ -79,6 +76,7 @@ plugin_init (GstPlugin * plugin)
gst_ffmpegenc_register (plugin); gst_ffmpegenc_register (plugin);
gst_ffmpegdec_register (plugin); gst_ffmpegdec_register (plugin);
#if 0
gst_ffmpegdemux_register (plugin); gst_ffmpegdemux_register (plugin);
gst_ffmpegmux_register (plugin); gst_ffmpegmux_register (plugin);
gst_ffmpegcsp_register (plugin); gst_ffmpegcsp_register (plugin);
@ -86,6 +84,7 @@ plugin_init (GstPlugin * plugin)
gst_ffmpegdeinterlace_register (plugin); gst_ffmpegdeinterlace_register (plugin);
register_protocol (&gstreamer_protocol); register_protocol (&gstreamer_protocol);
#endif
/* Now we can return the pointer to the newly created Plugin object. */ /* Now we can return the pointer to the newly created Plugin object. */
return TRUE; return TRUE;

View file

@ -1226,7 +1226,7 @@ gst_ffmpeg_caps_with_codecid (enum CodecID codec_id,
/* extradata parsing (esds [mpeg4], wma/wmv, msmpeg4v1/2/3, etc.) */ /* extradata parsing (esds [mpeg4], wma/wmv, msmpeg4v1/2/3, etc.) */
if ((value = gst_structure_get_value (str, "codec_data"))) { 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)); context->extradata = av_mallocz (GST_BUFFER_SIZE (buf));
memcpy (context->extradata, GST_BUFFER_DATA (buf), memcpy (context->extradata, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf)); GST_BUFFER_SIZE (buf));

View file

@ -61,7 +61,7 @@ struct _GstFFMpegDec
} audio; } audio;
} format; } format;
gboolean waiting_for_key; gboolean waiting_for_key;
guint64 next_ts; guint64 next_ts, synctime;
/* parsing */ /* parsing */
AVCodecParserContext *pctx; 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_init (GstFFMpegDec * ffmpegdec);
static void gst_ffmpegdec_dispose (GObject * object); static void gst_ffmpegdec_dispose (GObject * object);
static gboolean gst_ffmpegdec_query (GstPad * pad, GstQueryType type, static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery *query);
GstFormat * fmt, gint64 * value);
static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event); static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event);
static GstPadLinkReturn gst_ffmpegdec_connect (GstPad * pad, static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps);
const GstCaps * caps); static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event);
static void gst_ffmpegdec_chain (GstPad * pad, GstData * data); static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf);
static GstElementStateReturn gst_ffmpegdec_change_state (GstElement * element); 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); 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_object_class_install_property (gobject_class, ARG_SKIPFRAME,
g_param_spec_enum ("skip-frame", "Skip frames", g_param_spec_enum ("skip-frame", "Skip frames",
"Which types of frames to skip during decoding", "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", g_param_spec_enum ("lowres", "Low resolution",
"At which resolution to decode images", "At which resolution to decode images",
GST_FFMPEGDEC_TYPE_LOWRES, 0, G_PARAM_READWRITE)); 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 static void
@ -260,12 +259,13 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
/* setup pads */ /* setup pads */
ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); 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_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain);
gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad); gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);
ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); 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_pad_set_event_function (ffmpegdec->srcpad,
GST_DEBUG_FUNCPTR (gst_ffmpegdec_event)); GST_DEBUG_FUNCPTR (gst_ffmpegdec_event));
gst_pad_set_query_function (ffmpegdec->srcpad, gst_pad_set_query_function (ffmpegdec->srcpad,
@ -283,8 +283,6 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
ffmpegdec->hurry_up = ffmpegdec->lowres = 0; ffmpegdec->hurry_up = ffmpegdec->lowres = 0;
ffmpegdec->last_buffer = NULL; ffmpegdec->last_buffer = NULL;
GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE);
} }
static void static void
@ -302,19 +300,24 @@ gst_ffmpegdec_dispose (GObject * object)
} }
static gboolean static gboolean
gst_ffmpegdec_query (GstPad * pad, GstQueryType type, gst_ffmpegdec_query (GstPad * pad, GstQuery *query)
GstFormat * fmt, gint64 * value)
{ {
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); GstFFMpegDec *ffmpegdec;
GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad); GstPad *peer;
GstFormat bfmt = GST_FORMAT_BYTES; GstFormat bfmt;
bfmt = GST_FORMAT_BYTES;
ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
peer = GST_PAD_PEER (ffmpegdec->sinkpad);
if (!peer) 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; return TRUE;
#if 0
/* ok, do bitrate calc... */ /* ok, do bitrate calc... */
if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) || if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
*fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 || *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 ||
@ -324,15 +327,24 @@ gst_ffmpegdec_query (GstPad * pad, GstQueryType type,
if (ffmpegdec->pcache && type == GST_QUERY_POSITION) if (ffmpegdec->pcache && type == GST_QUERY_POSITION)
*value -= GST_BUFFER_SIZE (ffmpegdec->pcache); *value -= GST_BUFFER_SIZE (ffmpegdec->pcache);
*value *= GST_SECOND / ffmpegdec->context->bit_rate; *value *= GST_SECOND / ffmpegdec->context->bit_rate;
#endif
return TRUE; return FALSE;
no_peer:
{
return FALSE;
}
} }
static gboolean static gboolean
gst_ffmpegdec_event (GstPad * pad, GstEvent * event) gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
{ {
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad); GstFFMpegDec *ffmpegdec;
GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad); GstPad *peer;
ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
peer = GST_PAD_PEER (ffmpegdec->sinkpad);
if (!peer) if (!peer)
return FALSE; return FALSE;
@ -389,13 +401,10 @@ gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec)
GstFFMpegDecClass *oclass = GstFFMpegDecClass *oclass =
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
goto could_not_open;
ffmpegdec->opened = TRUE; 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); GST_LOG ("Opened ffmpeg codec %s", oclass->in_plugin->name);
@ -425,16 +434,25 @@ gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec)
break; break;
} }
ffmpegdec->next_ts = 0; ffmpegdec->next_ts = 0;
ffmpegdec->synctime = GST_CLOCK_TIME_NONE;
ffmpegdec->last_buffer = NULL; ffmpegdec->last_buffer = NULL;
return TRUE; 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 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 *oclass =
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
GstStructure *structure; GstStructure *structure;
@ -485,10 +503,10 @@ gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps)
g_free (ffmpegdec->par); g_free (ffmpegdec->par);
ffmpegdec->par = NULL; ffmpegdec->par = NULL;
} }
return GST_PAD_LINK_REFUSED; return FALSE;
} }
return GST_PAD_LINK_OK; return TRUE;
} }
static int static int
@ -528,7 +546,8 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
return avcodec_default_get_buffer(context, 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; ffmpegdec->last_buffer = buf;
gst_ffmpeg_avpicture_fill ((AVPicture *) picture, gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
@ -647,18 +666,18 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
} }
if (caps == NULL || 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), GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
("Failed to link ffmpeg decoder (%s) to next element", ("Failed to link ffmpeg decoder (%s) to next element",
oclass->in_plugin->name)); oclass->in_plugin->name));
if (caps != NULL) if (caps != NULL)
gst_caps_free (caps); gst_caps_unref (caps);
return FALSE; return FALSE;
} }
gst_caps_free (caps); gst_caps_unref (caps);
return TRUE; return TRUE;
} }
@ -671,6 +690,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
GstBuffer *outbuf = NULL; GstBuffer *outbuf = NULL;
gint have_data = 0, len = 0; gint have_data = 0, len = 0;
GstFlowReturn ret;
ffmpegdec->context->frame_number++; ffmpegdec->context->frame_number++;
@ -685,6 +705,43 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
GST_DEBUG_OBJECT (ffmpegdec, GST_DEBUG_OBJECT (ffmpegdec,
"Decode video: len=%d, have_data=%d", len, have_data); "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 && if (ffmpegdec->waiting_for_key &&
ffmpegdec->picture->pict_type != FF_I_TYPE) { ffmpegdec->picture->pict_type != FF_I_TYPE) {
have_data = 0; have_data = 0;
@ -705,7 +762,8 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
if (!gst_ffmpegdec_negotiate (ffmpegdec)) if (!gst_ffmpegdec_negotiate (ffmpegdec))
return -1; 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. /* original ffmpeg code does not handle odd sizes correctly.
* This patched up version does */ * This patched up version does */
@ -725,22 +783,8 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
ffmpegdec->waiting_for_key = FALSE; ffmpegdec->waiting_for_key = FALSE;
/* note that ffmpeg sometimes gets the FPS wrong. if (!ffmpegdec->picture->key_frame) {
* For B-frame containing movies, we get all pictures delayed GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
* 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);
} }
GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts; GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
@ -840,22 +884,20 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
} }
if (have_data) { if (have_data) {
GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%" GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
if (GST_PAD_IS_USABLE (ffmpegdec->srcpad)) gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
gst_pad_push (ffmpegdec->srcpad, GST_DATA (outbuf)); gst_pad_push (ffmpegdec->srcpad, outbuf);
else
gst_buffer_unref (outbuf);
} }
return len; return len;
} }
static void static gboolean
gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event) gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
{ {
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad);
GstFFMpegDecClass *oclass = GstFFMpegDecClass *oclass =
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
@ -874,30 +916,31 @@ gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event)
} while (try++ < 10); } while (try++ < 10);
} }
goto forward; goto forward;
case GST_EVENT_FLUSH: case GST_EVENT_FLUSH_START:
if (ffmpegdec->opened) { if (ffmpegdec->opened) {
avcodec_flush_buffers (ffmpegdec->context); avcodec_flush_buffers (ffmpegdec->context);
} }
goto forward; goto forward;
case GST_EVENT_DISCONTINUOUS: { case GST_EVENT_NEWSEGMENT: {
gint64 value; gint64 base, start, end;
gdouble rate;
GstFormat fmt;
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { gst_event_parse_newsegment (event, &rate, &fmt, &start, &end, &base);
ffmpegdec->next_ts = value; if (fmt == GST_FORMAT_TIME) {
ffmpegdec->next_ts = start;
GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT,
GST_TIME_ARGS (value)); GST_TIME_ARGS (start));
} else if (ffmpegdec->context->bit_rate && } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) {
gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) { ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate;
gboolean new_media;
ffmpegdec->next_ts = value * GST_SECOND / ffmpegdec->context->bit_rate;
GST_DEBUG_OBJECT (ffmpegdec, GST_DEBUG_OBJECT (ffmpegdec,
"Discont to byte %lld, time %" GST_TIME_FORMAT, "Discont to byte %lld, time %" GST_TIME_FORMAT,
value, GST_TIME_ARGS (ffmpegdec->next_ts)); start, GST_TIME_ARGS (ffmpegdec->next_ts));
new_media = GST_EVENT_DISCONT_NEW_MEDIA (event);
gst_event_unref (event); gst_event_unref (event);
event = gst_event_new_discontinuous (new_media, event = gst_event_new_newsegment (rate, fmt,
GST_FORMAT_TIME, ffmpegdec->next_ts, GST_FORMAT_UNDEFINED); start * GST_SECOND / ffmpegdec->context->bit_rate,
end * GST_SECOND / ffmpegdec->context->bit_rate,
base * GST_SECOND / ffmpegdec->context->bit_rate);
} else { } else {
GST_WARNING_OBJECT (ffmpegdec, GST_WARNING_OBJECT (ffmpegdec,
"Received discont with no useful value..."); "Received discont with no useful value...");
@ -911,41 +954,30 @@ gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event)
ffmpegdec->waiting_for_key = TRUE; ffmpegdec->waiting_for_key = TRUE;
} }
} }
ffmpegdec->waiting_for_key = TRUE;
ffmpegdec->synctime = ffmpegdec->next_ts;
/* fall-through */ /* fall-through */
} }
default: default:
forward: forward:
gst_pad_event_default (ffmpegdec->sinkpad, event); return gst_pad_event_default (ffmpegdec->sinkpad, event);
return;
} }
return TRUE;
} }
static void static GstFlowReturn
gst_ffmpegdec_chain (GstPad * pad, GstData * _data) gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
{ {
GstBuffer *inbuf; GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad));
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
GstFFMpegDecClass *oclass = GstFFMpegDecClass *oclass =
(GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
guint8 *bdata, *data; guint8 *bdata, *data;
gint bsize, size, len, have_data; gint bsize, size, len, have_data;
guint64 in_ts; guint64 in_ts = GST_BUFFER_TIMESTAMP (inbuf);
/* event handling */ if (!ffmpegdec->opened)
if (GST_IS_EVENT (_data)) { goto not_negotiated;
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;
}
GST_DEBUG_OBJECT (ffmpegdec, GST_DEBUG_OBJECT (ffmpegdec,
"Received new data of size %d, time %" GST_TIME_FORMAT, "Received new data of size %d, time %" GST_TIME_FORMAT,
@ -953,7 +985,8 @@ gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
/* parse cache joining */ /* parse cache joining */
if (ffmpegdec->pcache) { 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; ffmpegdec->pcache = NULL;
bdata = GST_BUFFER_DATA (inbuf); bdata = GST_BUFFER_DATA (inbuf);
bsize = GST_BUFFER_SIZE (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). */ * ffmpeg devs know about it and will fix it (they said). */
else if (oclass->in_plugin->id == CODEC_ID_SVQ1 || else if (oclass->in_plugin->id == CODEC_ID_SVQ1 ||
oclass->in_plugin->id == CODEC_ID_SVQ3) { 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); bdata = GST_BUFFER_DATA (inbuf);
bsize = GST_BUFFER_SIZE (inbuf); bsize = GST_BUFFER_SIZE (inbuf);
} else { } else {
@ -1023,6 +1056,17 @@ gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize); GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
} }
gst_buffer_unref (inbuf); 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 static GstElementStateReturn
@ -1030,6 +1074,9 @@ gst_ffmpegdec_change_state (GstElement * element)
{ {
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element; GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element;
gint transition = GST_STATE_TRANSITION (element); gint transition = GST_STATE_TRANSITION (element);
GstElementStateReturn ret;
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (transition) { switch (transition) {
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
@ -1039,12 +1086,11 @@ gst_ffmpegdec_change_state (GstElement * element)
ffmpegdec->last_buffer = NULL; ffmpegdec->last_buffer = NULL;
} }
break; break;
default:
break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) return ret;
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
} }
static void static void
@ -1141,8 +1187,8 @@ gst_ffmpegdec_register (GstPlugin * plugin)
srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL); srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL);
} }
if (!sinkcaps || !srccaps) { if (!sinkcaps || !srccaps) {
if (sinkcaps) gst_caps_free (sinkcaps); if (sinkcaps) gst_caps_unref (sinkcaps);
if (srccaps) gst_caps_free (srccaps); if (srccaps) gst_caps_unref (srccaps);
goto next; goto next;
} }

View file

@ -132,11 +132,10 @@ static void gst_ffmpegenc_base_init (GstFFMpegEncClass * klass);
static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc); static void gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc);
static void gst_ffmpegenc_dispose (GObject * object); static void gst_ffmpegenc_dispose (GObject * object);
static GstPadLinkReturn gst_ffmpegenc_link (GstPad * pad, static gboolean gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps);
const GstCaps * caps);
static GstCaps * gst_ffmpegenc_getcaps (GstPad * pad); static GstCaps * gst_ffmpegenc_getcaps (GstPad * pad);
static void gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data); static GstFlowReturn gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer *buffer);
static void gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data); static GstFlowReturn gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer *buffer);
static void gst_ffmpegenc_set_property (GObject * object, static void gst_ffmpegenc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec); 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); 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) { if (klass->in_plugin->type == CODEC_TYPE_VIDEO) {
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE,
g_param_spec_ulong ("bitrate", "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)); "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; gstelement_class->change_state = gst_ffmpegenc_change_state;
gobject_class->dispose = gst_ffmpegenc_dispose; gobject_class->dispose = gst_ffmpegenc_dispose;
@ -243,10 +242,10 @@ gst_ffmpegenc_init (GstFFMpegEnc * ffmpegenc)
/* setup pads */ /* setup pads */
ffmpegenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink"); 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); gst_pad_set_getcaps_function (ffmpegenc->sinkpad, gst_ffmpegenc_getcaps);
ffmpegenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src"); 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 */ /* ffmpeg objects */
ffmpegenc->context = avcodec_alloc_context (); ffmpegenc->context = avcodec_alloc_context ();
@ -290,7 +289,7 @@ gst_ffmpegenc_dispose (GObject * object)
static GstCaps * static GstCaps *
gst_ffmpegenc_getcaps (GstPad * pad) gst_ffmpegenc_getcaps (GstPad * pad)
{ {
GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) gst_pad_get_parent (pad); GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad);
GstFFMpegEncClass *oclass = GstFFMpegEncClass *oclass =
(GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
AVCodecContext *ctx; AVCodecContext *ctx;
@ -348,14 +347,14 @@ gst_ffmpegenc_getcaps (GstPad * pad)
return caps; return caps;
} }
static GstPadLinkReturn static gboolean
gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps) gst_ffmpegenc_setcaps (GstPad * pad, GstCaps * caps)
{ {
GstCaps *other_caps; GstCaps *other_caps;
GstCaps *allowed_caps; GstCaps *allowed_caps;
GstCaps *icaps; GstCaps *icaps;
enum PixelFormat pix_fmt; enum PixelFormat pix_fmt;
GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) gst_pad_get_parent (pad); GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) GST_PAD_PARENT (pad);
GstFFMpegEncClass *oclass = GstFFMpegEncClass *oclass =
(GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc); (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); icaps = gst_caps_intersect (allowed_caps, other_caps);
gst_caps_free (allowed_caps); gst_caps_unref (allowed_caps);
gst_caps_free (other_caps); gst_caps_unref (other_caps);
if (gst_caps_is_empty (icaps)) { if (gst_caps_is_empty (icaps)) {
gst_caps_free (icaps); gst_caps_unref (icaps);
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
} }
@ -438,18 +437,16 @@ gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps)
newcaps = newcaps =
gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps, gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (icaps,
0)), NULL); 0)), NULL);
gst_caps_free (icaps); gst_caps_unref (icaps);
icaps = newcaps; icaps = newcaps;
} }
/* FIXME set_explicit_caps is not supposed to be used in a pad link if (!gst_pad_set_caps (ffmpegenc->srcpad, icaps)) {
* function. */
if (!gst_pad_set_explicit_caps (ffmpegenc->srcpad, icaps)) {
avcodec_close (ffmpegenc->context); avcodec_close (ffmpegenc->context);
gst_caps_free (icaps); gst_caps_unref (icaps);
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
} }
gst_caps_free (icaps); gst_caps_unref (icaps);
/* success! */ /* success! */
ffmpegenc->opened = TRUE; ffmpegenc->opened = TRUE;
@ -457,15 +454,14 @@ gst_ffmpegenc_link (GstPad * pad, const GstCaps * caps)
return GST_PAD_LINK_OK; return GST_PAD_LINK_OK;
} }
static void static GstFlowReturn
gst_ffmpegenc_chain_video (GstPad * pad, GstData * _data) gst_ffmpegenc_chain_video (GstPad * pad, GstBuffer * inbuf)
{ {
GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (gst_pad_get_parent (pad)); GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (GST_PAD_PARENT (pad));
GstBuffer *inbuf = GST_BUFFER (_data), *outbuf; GstBuffer *outbuf;
GstFFMpegEncClass *oclass = GstFFMpegEncClass *oclass =
(GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc)); (GstFFMpegEncClass *) (G_OBJECT_GET_CLASS (ffmpegenc));
gint ret_size = 0, frame_size; gint ret_size = 0, frame_size;
const AVRational bq = { 1, 1000000000 };
/* FIXME: events (discont (flush!) and eos (close down) etc.) */ /* 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), GST_BUFFER_DATA (inbuf),
ffmpegenc->context->pix_fmt, ffmpegenc->context->pix_fmt,
ffmpegenc->context->width, ffmpegenc->context->height); 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 = ffmpegenc->picture->pts =
gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (inbuf), 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); outbuf = gst_buffer_new_and_alloc (ffmpegenc->buffer_size);
ret_size = avcodec_encode_video (ffmpegenc->context, ret_size = avcodec_encode_video (ffmpegenc->context,
GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (outbuf),
GST_BUFFER_MAXSIZE (outbuf), ffmpegenc->picture); GST_BUFFER_SIZE (outbuf), ffmpegenc->picture);
if (ret_size < 0) { if (ret_size < 0) {
GST_ERROR_OBJECT (ffmpegenc, GST_ERROR_OBJECT (ffmpegenc,
"ffenc_%s: failed to encode buffer", oclass->in_plugin->name); "ffenc_%s: failed to encode buffer", oclass->in_plugin->name);
gst_buffer_unref (inbuf); gst_buffer_unref (inbuf);
gst_buffer_unref (outbuf); gst_buffer_unref (outbuf);
return; return GST_FLOW_OK;
} }
GST_BUFFER_SIZE (outbuf) = ret_size; GST_BUFFER_SIZE (outbuf) = ret_size;
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf); GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf); GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
if (ffmpegenc->context->coded_frame->key_frame) if (!ffmpegenc->context->coded_frame->key_frame)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
else gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegenc->srcpad));
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DELTA_UNIT);
gst_pad_push (ffmpegenc->srcpad, GST_DATA (outbuf));
gst_buffer_unref (inbuf); return gst_pad_push (ffmpegenc->srcpad, outbuf);
} }
static void static GstFlowReturn
gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data) gst_ffmpegenc_chain_audio (GstPad * pad, GstBuffer * inbuf)
{ {
GstBuffer *inbuf = GST_BUFFER (_data);
GstBuffer *outbuf = NULL, *subbuf; 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; gint size, ret_size = 0, in_size, frame_size;
GstFlowReturn ret;
size = GST_BUFFER_SIZE (inbuf); size = GST_BUFFER_SIZE (inbuf);
@ -537,7 +531,8 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data)
if (in_size > size) { if (in_size > size) {
/* this is panic! we got a buffer, but still don't have enough /* this is panic! we got a buffer, but still don't have enough
* data. Merge them and retry in the next cycle... */ * 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) { } else if (in_size == size) {
/* exactly the same! how wonderful */ /* exactly the same! how wonderful */
ffmpegenc->cache = inbuf; ffmpegenc->cache = inbuf;
@ -554,8 +549,7 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data)
} else { } else {
gst_buffer_unref (inbuf); gst_buffer_unref (inbuf);
} }
return GST_FLOW_OK;
return;
} }
/* create the frame */ /* 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)); subbuf = gst_buffer_create_sub (inbuf, 0, frame_size - (in_size - size));
GST_BUFFER_DURATION (subbuf) = GST_BUFFER_DURATION (subbuf) =
GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size; 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; ffmpegenc->cache = NULL;
} else { } else {
subbuf = gst_buffer_create_sub (inbuf, size - in_size, frame_size); 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)); outbuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (inbuf));
ret_size = avcodec_encode_audio (ffmpegenc->context, ret_size = avcodec_encode_audio (ffmpegenc->context,
GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (outbuf),
GST_BUFFER_MAXSIZE (outbuf), (const short int *) GST_BUFFER_SIZE (outbuf), (const short int *)
GST_BUFFER_DATA (subbuf)); GST_BUFFER_DATA (subbuf));
if (ret_size < 0) { if (ret_size < 0) {
@ -586,17 +581,20 @@ gst_ffmpegenc_chain_audio (GstPad * pad, GstData * _data)
gst_buffer_unref (inbuf); gst_buffer_unref (inbuf);
gst_buffer_unref (outbuf); gst_buffer_unref (outbuf);
gst_buffer_unref (subbuf); gst_buffer_unref (subbuf);
return; return GST_FLOW_OK;
} }
GST_BUFFER_SIZE (outbuf) = ret_size; GST_BUFFER_SIZE (outbuf) = ret_size;
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (subbuf); GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (subbuf);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (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; in_size -= frame_size;
gst_buffer_unref (subbuf);
} }
return ret;
} }
static void static void

View file

@ -1,17 +1,16 @@
#plugin_LTLIBRARIES = libgstpostproc.la
plugin_LTLIBRARIES = libgstpostproc.la #
#libgstpostproc_la_SOURCES = gstpostproc.c
libgstpostproc_la_SOURCES = gstpostproc.c #
#libgstpostproc_la_CFLAGS = $(GST_CFLAGS) \
libgstpostproc_la_CFLAGS = $(GST_CFLAGS) \ # -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \
-I $(top_srcdir)/gst-libs/ext/ffmpeg/libavformat \ # -I $(top_srcdir)/gst-libs/ext/ffmpeg/libavcodec
-I $(top_srcdir)/gst-libs/ext/ffmpeg/libavcodec #libgstpostproc_la_LIBADD = \
libgstpostproc_la_LIBADD = \ # $(top_builddir)/gst-libs/ext/ffmpeg/libavformat/libavformat.la \
$(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/libavcodec.la
# $(top_builddir)/gst-libs/ext/ffmpeg/libavcodec/libpostproc/libffpostproc.la # $(top_builddir)/gst-libs/ext/ffmpeg/libavcodec/libpostproc/libffpostproc.la
#
libgstpostproc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) #libgstpostproc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
#
noinst_HEADERS = \ #noinst_HEADERS = \
gstpostproc.h # gstpostproc.h