ext/ffmpeg/gstffmpegdec.c: Implement B-frame skipping and low-resolution decoding (useful for very slow CPUs).

Original commit message from CVS:
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_lowres_get_type),
(gst_ffmpegdec_skipframe_get_type), (gst_ffmpegdec_class_init),
(gst_ffmpegdec_init), (gst_ffmpegdec_connect),
(gst_ffmpegdec_frame), (gst_ffmpegdec_set_property),
(gst_ffmpegdec_get_property):
Implement B-frame skipping and low-resolution decoding (useful
for very slow CPUs).
This commit is contained in:
Ronald S. Bultje 2005-01-31 10:45:20 +00:00
parent 68331a35b5
commit d40aa0a0df
2 changed files with 131 additions and 15 deletions

View file

@ -1,3 +1,13 @@
2005-01-31 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_lowres_get_type),
(gst_ffmpegdec_skipframe_get_type), (gst_ffmpegdec_class_init),
(gst_ffmpegdec_init), (gst_ffmpegdec_connect),
(gst_ffmpegdec_frame), (gst_ffmpegdec_set_property),
(gst_ffmpegdec_get_property):
Implement B-frame skipping and low-resolution decoding (useful
for very slow CPUs).
2005-01-28 Ronald S. Bultje <rbultje@ronald.bitfreak.net> 2005-01-28 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_register): * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_register):

View file

@ -64,6 +64,8 @@ struct _GstFFMpegDec
GstBuffer *pcache; GstBuffer *pcache;
GValue *par; /* pixel aspect ratio of incoming data */ GValue *par; /* pixel aspect ratio of incoming data */
gint hurry_up, lowres;
}; };
typedef struct _GstFFMpegDecClass GstFFMpegDecClass; typedef struct _GstFFMpegDecClass GstFFMpegDecClass;
@ -95,16 +97,11 @@ struct _GstFFMpegDecClassParams
#define GST_IS_FFMPEGDEC_CLASS(obj) \ #define GST_IS_FFMPEGDEC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC))
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum enum
{ {
ARG_0, ARG_0,
/* FILL ME */ ARG_LOWRES,
ARG_SKIPFRAME
}; };
static GHashTable *global_plugins; static GHashTable *global_plugins;
@ -125,6 +122,11 @@ static void gst_ffmpegdec_chain (GstPad * pad, GstData * data);
static GstElementStateReturn gst_ffmpegdec_change_state (GstElement * element); static GstElementStateReturn gst_ffmpegdec_change_state (GstElement * element);
static void gst_ffmpegdec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_ffmpegdec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
#if 0 #if 0
/* some sort of bufferpool handling, but different */ /* some sort of bufferpool handling, but different */
static int gst_ffmpegdec_get_buffer (AVCodecContext * context, static int gst_ffmpegdec_get_buffer (AVCodecContext * context,
@ -135,7 +137,48 @@ static void gst_ffmpegdec_release_buffer (AVCodecContext * context,
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
/*static guint gst_ffmpegdec_signals[LAST_SIGNAL] = { 0 }; */ #define GST_FFMPEGDEC_TYPE_LOWRES (gst_ffmpegdec_lowres_get_type())
static GType
gst_ffmpegdec_lowres_get_type (void)
{
static GType ffmpegdec_lowres_type = 0;
if (!ffmpegdec_lowres_type) {
static GEnumValue ffmpegdec_lowres[] = {
{0, "0", "full"},
{1, "1", "1/2-size"},
{2, "2", "1/4-size"},
{0, NULL, NULL},
};
ffmpegdec_lowres_type =
g_enum_register_static ("GstFFMpegDecLowres", ffmpegdec_lowres);
}
return ffmpegdec_lowres_type;
}
#define GST_FFMPEGDEC_TYPE_SKIPFRAME (gst_ffmpegdec_skipframe_get_type())
static GType
gst_ffmpegdec_skipframe_get_type (void)
{
static GType ffmpegdec_skipframe_type = 0;
if (!ffmpegdec_skipframe_type) {
static GEnumValue ffmpegdec_skipframe[] = {
{0, "0", "Skip nothing"},
{1, "1", "Skip B-frames"},
{2, "2", "Skip IDCT/Dequantization"},
{5, "5", "Skip everything"},
{0, NULL, NULL},
};
ffmpegdec_skipframe_type =
g_enum_register_static ("GstFFMpegDecSkipFrame", ffmpegdec_skipframe);
}
return ffmpegdec_skipframe_type;
}
static void static void
gst_ffmpegdec_base_init (GstFFMpegDecClass * klass) gst_ffmpegdec_base_init (GstFFMpegDecClass * klass)
@ -183,15 +226,23 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass)
static void static void
gst_ffmpegdec_class_init (GstFFMpegDecClass * klass) gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class; GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
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",
GST_FFMPEGDEC_TYPE_SKIPFRAME, 0, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_LOWRES,
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->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; gstelement_class->change_state = gst_ffmpegdec_change_state;
} }
@ -218,12 +269,11 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
/* some ffmpeg data */ /* some ffmpeg data */
ffmpegdec->context = avcodec_alloc_context (); ffmpegdec->context = avcodec_alloc_context ();
ffmpegdec->picture = avcodec_alloc_frame (); ffmpegdec->picture = avcodec_alloc_frame ();
ffmpegdec->pctx = NULL; ffmpegdec->pctx = NULL;
ffmpegdec->pcache = NULL; ffmpegdec->pcache = NULL;
ffmpegdec->par = NULL; ffmpegdec->par = NULL;
ffmpegdec->opened = FALSE; ffmpegdec->opened = FALSE;
ffmpegdec->hurry_up = ffmpegdec->lowres = 0;
GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE); GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE);
} }
@ -408,6 +458,10 @@ gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps)
/* workaround encoder bugs */ /* workaround encoder bugs */
ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT; ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;
/* for slow cpus */
ffmpegdec->context->lowres = ffmpegdec->lowres;
ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;
/* open codec - we don't select an output pix_fmt yet, /* open codec - we don't select an output pix_fmt yet,
* simply because we don't know! We only get it * simply because we don't know! We only get it
* during playback... */ * during playback... */
@ -571,6 +625,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
switch (oclass->in_plugin->type) { switch (oclass->in_plugin->type) {
case CODEC_TYPE_VIDEO: case CODEC_TYPE_VIDEO:
ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
len = avcodec_decode_video (ffmpegdec->context, len = avcodec_decode_video (ffmpegdec->context,
ffmpegdec->picture, &have_data, data, size); ffmpegdec->picture, &have_data, data, size);
GST_DEBUG_OBJECT (ffmpegdec, GST_DEBUG_OBJECT (ffmpegdec,
@ -615,6 +670,17 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
ffmpegdec->context->frame_rate_base / ffmpegdec->context->frame_rate_base /
ffmpegdec->context->frame_rate; ffmpegdec->context->frame_rate;
ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf); ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
} else if (ffmpegdec->picture->pict_type != -1) {
/* update time for skip-frame */
if (ffmpegdec->picture->pict_type == FF_I_TYPE &&
GST_CLOCK_TIME_IS_VALID (*in_ts) &&
ffmpegdec->context->frame_rate > 0) {
ffmpegdec->next_ts = *in_ts;
} else {
ffmpegdec->next_ts += GST_SECOND *
ffmpegdec->context->frame_rate_base /
ffmpegdec->context->frame_rate;
}
} }
break; break;
@ -852,6 +918,46 @@ gst_ffmpegdec_change_state (GstElement * element)
return GST_STATE_SUCCESS; return GST_STATE_SUCCESS;
} }
static void
gst_ffmpegdec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
switch (prop_id) {
case ARG_LOWRES:
ffmpegdec->lowres = ffmpegdec->context->lowres =
g_value_get_enum (value);
break;
case ARG_SKIPFRAME:
ffmpegdec->hurry_up = ffmpegdec->context->hurry_up =
g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_ffmpegdec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
switch (prop_id) {
case ARG_LOWRES:
g_value_set_enum (value, ffmpegdec->context->lowres);
break;
case ARG_SKIPFRAME:
g_value_set_enum (value, ffmpegdec->context->hurry_up);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
gboolean gboolean
gst_ffmpegdec_register (GstPlugin * plugin) gst_ffmpegdec_register (GstPlugin * plugin)
{ {