mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 22:36:33 +00:00
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:
parent
68331a35b5
commit
d40aa0a0df
2 changed files with 131 additions and 15 deletions
10
ChangeLog
10
ChangeLog
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue