mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-07 06:52:41 +00:00
ext/mpeg2dec/gstmpeg2dec.*: Fix padtemplate as we can now do fractional framerates.
Original commit message from CVS: * ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_base_init), (gst_mpeg2dec_class_init), (gst_mpeg2dec_init), (gst_mpeg2dec_finalize), (gst_mpeg2dec_reset), (gst_mpeg2dec_qos_reset), (gst_mpeg2dec_alloc_buffer), (gst_mpeg2dec_negotiate_format), (init_dummybuf), (handle_sequence), (handle_picture), (handle_slice), (gst_mpeg2dec_chain), (gst_mpeg2dec_sink_event), (gst_mpeg2dec_src_event), (gst_mpeg2dec_change_state): * ext/mpeg2dec/gstmpeg2dec.h: Fix padtemplate as we can now do fractional framerates. Small cleanups. Use GstSegment. Add simple frame dropping QoS. Precalc buffer output sizes and UV offsets. Always give libmpeg2 a valid fbuf when it wants one. don't trust libmpeg to discard our buffers but manage it ourselves. Fixes #343627, #327350, #335288
This commit is contained in:
parent
252d48f7d3
commit
78d4166a4f
4 changed files with 401 additions and 284 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
2006-06-07 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_base_init),
|
||||||
|
(gst_mpeg2dec_class_init), (gst_mpeg2dec_init),
|
||||||
|
(gst_mpeg2dec_finalize), (gst_mpeg2dec_reset),
|
||||||
|
(gst_mpeg2dec_qos_reset), (gst_mpeg2dec_alloc_buffer),
|
||||||
|
(gst_mpeg2dec_negotiate_format), (init_dummybuf),
|
||||||
|
(handle_sequence), (handle_picture), (handle_slice),
|
||||||
|
(gst_mpeg2dec_chain), (gst_mpeg2dec_sink_event),
|
||||||
|
(gst_mpeg2dec_src_event), (gst_mpeg2dec_change_state):
|
||||||
|
* ext/mpeg2dec/gstmpeg2dec.h:
|
||||||
|
Fix padtemplate as we can now do fractional framerates.
|
||||||
|
Small cleanups.
|
||||||
|
Use GstSegment.
|
||||||
|
Add simple frame dropping QoS.
|
||||||
|
Precalc buffer output sizes and UV offsets.
|
||||||
|
Always give libmpeg2 a valid fbuf when it wants one.
|
||||||
|
don't trust libmpeg to discard our buffers but manage it
|
||||||
|
ourselves.
|
||||||
|
Fixes #343627, #327350, #335288
|
||||||
|
|
||||||
2006-06-05 Sebastien Moutte <sebastien@moutte.net>
|
2006-06-05 Sebastien Moutte <sebastien@moutte.net>
|
||||||
|
|
||||||
* win32/MANIFEST:
|
* win32/MANIFEST:
|
||||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit 4282dfa89d50e80f59d4e1837af95fbf74e75d18
|
Subproject commit 5d58e7652bf38a637dceca167d6e47e7794b2b52
|
|
@ -66,61 +66,6 @@ GST_ELEMENT_DETAILS ("mpeg1 and mpeg2 video decoder",
|
||||||
*/
|
*/
|
||||||
#define MAX_ERROR_COUNT (5)
|
#define MAX_ERROR_COUNT (5)
|
||||||
|
|
||||||
/*
|
|
||||||
* We can't use fractions in static pad templates, so
|
|
||||||
* we do something manual...
|
|
||||||
* FIXME: This is no longer true. We could use a normal pad template
|
|
||||||
* now
|
|
||||||
*/
|
|
||||||
static GstPadTemplate *
|
|
||||||
src_templ (void)
|
|
||||||
{
|
|
||||||
static GstPadTemplate *templ = NULL;
|
|
||||||
|
|
||||||
if (!templ) {
|
|
||||||
GstCaps *caps;
|
|
||||||
GstStructure *structure;
|
|
||||||
GValue list = { 0 }
|
|
||||||
, fps = {
|
|
||||||
0}
|
|
||||||
, fmt = {
|
|
||||||
0};
|
|
||||||
char *fmts[] = { "YV12", "I420", "Y42B", NULL };
|
|
||||||
guint n;
|
|
||||||
|
|
||||||
caps = gst_caps_new_simple ("video/x-raw-yuv",
|
|
||||||
"format", GST_TYPE_FOURCC,
|
|
||||||
GST_MAKE_FOURCC ('I', '4', '2', '0'),
|
|
||||||
"width", GST_TYPE_INT_RANGE, 16, 4096,
|
|
||||||
"height", GST_TYPE_INT_RANGE, 16, 4096, NULL);
|
|
||||||
|
|
||||||
structure = gst_caps_get_structure (caps, 0);
|
|
||||||
|
|
||||||
g_value_init (&list, GST_TYPE_LIST);
|
|
||||||
g_value_init (&fps, GST_TYPE_FRACTION);
|
|
||||||
for (n = 0; fpss[n][0] != 0; n++) {
|
|
||||||
gst_value_set_fraction (&fps, fpss[n][0], fpss[n][1]);
|
|
||||||
gst_value_list_append_value (&list, &fps);
|
|
||||||
}
|
|
||||||
gst_structure_set_value (structure, "framerate", &list);
|
|
||||||
g_value_unset (&list);
|
|
||||||
g_value_unset (&fps);
|
|
||||||
|
|
||||||
g_value_init (&list, GST_TYPE_LIST);
|
|
||||||
g_value_init (&fmt, GST_TYPE_FOURCC);
|
|
||||||
for (n = 0; fmts[n] != NULL; n++) {
|
|
||||||
gst_value_set_fourcc (&fmt, GST_STR_FOURCC (fmts[n]));
|
|
||||||
gst_value_list_append_value (&list, &fmt);
|
|
||||||
}
|
|
||||||
gst_structure_set_value (structure, "format", &list);
|
|
||||||
g_value_unset (&list);
|
|
||||||
g_value_unset (&fmt);
|
|
||||||
|
|
||||||
templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
|
|
||||||
}
|
|
||||||
return templ;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef enable_user_data
|
#ifdef enable_user_data
|
||||||
static GstStaticPadTemplate user_data_template_factory =
|
static GstStaticPadTemplate user_data_template_factory =
|
||||||
GST_STATIC_PAD_TEMPLATE ("user_data",
|
GST_STATIC_PAD_TEMPLATE ("user_data",
|
||||||
|
@ -137,11 +82,22 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
"mpegversion = (int) [ 1, 2 ], " "systemstream = (boolean) false")
|
"mpegversion = (int) [ 1, 2 ], " "systemstream = (boolean) false")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate src_template_factory =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_STATIC_CAPS ("video/x-raw-yuv, "
|
||||||
|
"format = (fourcc) { YV12, I420, Y42B }, "
|
||||||
|
"width = (int) [ 16, 4096 ], "
|
||||||
|
"height = (int) [ 16, 4096 ], "
|
||||||
|
"framerate = (fraction) { 24000/1001, 24/1, 25/1, 30000/1001, 30/1, 50/1, 60000/1001, 60/1 }")
|
||||||
|
);
|
||||||
|
|
||||||
static void gst_mpeg2dec_base_init (gpointer g_class);
|
static void gst_mpeg2dec_base_init (gpointer g_class);
|
||||||
static void gst_mpeg2dec_class_init (GstMpeg2decClass * klass);
|
static void gst_mpeg2dec_class_init (GstMpeg2decClass * klass);
|
||||||
static void gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec);
|
static void gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec);
|
||||||
|
|
||||||
static void gst_mpeg2dec_dispose (GObject * object);
|
static void gst_mpeg2dec_finalize (GObject * object);
|
||||||
static void gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec);
|
static void gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec);
|
||||||
|
|
||||||
static void gst_mpeg2dec_set_property (GObject * object, guint prop_id,
|
static void gst_mpeg2dec_set_property (GObject * object, guint prop_id,
|
||||||
|
@ -168,7 +124,6 @@ static gboolean gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event);
|
||||||
static GstFlowReturn gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf);
|
static GstFlowReturn gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf);
|
||||||
|
|
||||||
//static gboolean gst_mpeg2dec_sink_query (GstPad * pad, GstQuery * query);
|
//static gboolean gst_mpeg2dec_sink_query (GstPad * pad, GstQuery * query);
|
||||||
static GstCaps *gst_mpeg2dec_src_getcaps (GstPad * pad);
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static const GstFormat *gst_mpeg2dec_get_formats (GstPad * pad);
|
static const GstFormat *gst_mpeg2dec_get_formats (GstPad * pad);
|
||||||
|
@ -218,7 +173,8 @@ gst_mpeg2dec_base_init (gpointer g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
gst_element_class_add_pad_template (element_class, src_templ ());
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
gst_static_pad_template_get (&src_template_factory));
|
||||||
gst_element_class_add_pad_template (element_class,
|
gst_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&sink_template_factory));
|
gst_static_pad_template_get (&sink_template_factory));
|
||||||
#ifdef enable_user_data
|
#ifdef enable_user_data
|
||||||
|
@ -241,7 +197,7 @@ gst_mpeg2dec_class_init (GstMpeg2decClass * klass)
|
||||||
|
|
||||||
gobject_class->set_property = gst_mpeg2dec_set_property;
|
gobject_class->set_property = gst_mpeg2dec_set_property;
|
||||||
gobject_class->get_property = gst_mpeg2dec_get_property;
|
gobject_class->get_property = gst_mpeg2dec_get_property;
|
||||||
gobject_class->dispose = gst_mpeg2dec_dispose;
|
gobject_class->finalize = gst_mpeg2dec_finalize;
|
||||||
|
|
||||||
gstelement_class->change_state = gst_mpeg2dec_change_state;
|
gstelement_class->change_state = gst_mpeg2dec_change_state;
|
||||||
gstelement_class->set_index = gst_mpeg2dec_set_index;
|
gstelement_class->set_index = gst_mpeg2dec_set_index;
|
||||||
|
@ -255,24 +211,27 @@ gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
|
||||||
mpeg2dec->sinkpad =
|
mpeg2dec->sinkpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get
|
gst_pad_new_from_template (gst_static_pad_template_get
|
||||||
(&sink_template_factory), "sink");
|
(&sink_template_factory), "sink");
|
||||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
|
|
||||||
gst_pad_set_chain_function (mpeg2dec->sinkpad,
|
gst_pad_set_chain_function (mpeg2dec->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_chain));
|
||||||
//gst_pad_set_query_function (mpeg2dec->sinkpad,
|
#if 0
|
||||||
// GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_query));
|
gst_pad_set_query_function (mpeg2dec->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_sink_query));
|
||||||
|
#endif
|
||||||
gst_pad_set_event_function (mpeg2dec->sinkpad,
|
gst_pad_set_event_function (mpeg2dec->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_sink_event));
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_sink_event));
|
||||||
|
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->sinkpad);
|
||||||
|
|
||||||
mpeg2dec->srcpad = gst_pad_new_from_template (src_templ (), "src");
|
mpeg2dec->srcpad =
|
||||||
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
|
gst_pad_new_from_template (gst_static_pad_template_get
|
||||||
gst_pad_set_getcaps_function (mpeg2dec->srcpad,
|
(&src_template_factory), "src");
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_getcaps));
|
|
||||||
gst_pad_set_event_function (mpeg2dec->srcpad,
|
gst_pad_set_event_function (mpeg2dec->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_event));
|
||||||
gst_pad_set_query_type_function (mpeg2dec->srcpad,
|
gst_pad_set_query_type_function (mpeg2dec->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_get_src_query_types));
|
||||||
gst_pad_set_query_function (mpeg2dec->srcpad,
|
gst_pad_set_query_function (mpeg2dec->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
|
GST_DEBUG_FUNCPTR (gst_mpeg2dec_src_query));
|
||||||
|
gst_pad_use_fixed_caps (mpeg2dec->srcpad);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (mpeg2dec), mpeg2dec->srcpad);
|
||||||
|
|
||||||
#ifdef enable_user_data
|
#ifdef enable_user_data
|
||||||
mpeg2dec->userdatapad =
|
mpeg2dec->userdatapad =
|
||||||
|
@ -287,7 +246,7 @@ gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpeg2dec_dispose (GObject * object)
|
gst_mpeg2dec_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
|
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
|
||||||
|
|
||||||
|
@ -296,8 +255,10 @@ gst_mpeg2dec_dispose (GObject * object)
|
||||||
mpeg2_close (mpeg2dec->decoder);
|
mpeg2_close (mpeg2dec->decoder);
|
||||||
mpeg2dec->decoder = NULL;
|
mpeg2dec->decoder = NULL;
|
||||||
}
|
}
|
||||||
|
g_free (mpeg2dec->dummybuf[0]);
|
||||||
|
mpeg2dec->dummybuf[0] = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -307,8 +268,7 @@ gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
|
||||||
mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
|
mpeg2dec->format = MPEG2DEC_FORMAT_NONE;
|
||||||
mpeg2dec->width = -1;
|
mpeg2dec->width = -1;
|
||||||
mpeg2dec->height = -1;
|
mpeg2dec->height = -1;
|
||||||
mpeg2dec->segment_start = 0;
|
gst_segment_init (&mpeg2dec->segment, GST_FORMAT_UNDEFINED);
|
||||||
mpeg2dec->segment_end = -1;
|
|
||||||
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
|
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
|
||||||
mpeg2dec->frame_period = 0;
|
mpeg2dec->frame_period = 0;
|
||||||
mpeg2dec->need_sequence = TRUE;
|
mpeg2dec->need_sequence = TRUE;
|
||||||
|
@ -318,6 +278,15 @@ gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
|
||||||
mpeg2_reset (mpeg2dec->decoder, 1);
|
mpeg2_reset (mpeg2dec->decoder, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_mpeg2dec_qos_reset (GstMpeg2dec * mpeg2dec)
|
||||||
|
{
|
||||||
|
GST_OBJECT_LOCK (mpeg2dec);
|
||||||
|
mpeg2dec->proportion = 1.0;
|
||||||
|
mpeg2dec->earliest_time = -1;
|
||||||
|
GST_OBJECT_UNLOCK (mpeg2dec);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpeg2dec_set_index (GstElement * element, GstIndex * index)
|
gst_mpeg2dec_set_index (GstElement * element, GstIndex * index)
|
||||||
{
|
{
|
||||||
|
@ -492,48 +461,19 @@ gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, gint64 offset,
|
||||||
GstBuffer ** obuf)
|
GstBuffer ** obuf)
|
||||||
{
|
{
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
gint size;
|
guint8 *buf[3];
|
||||||
guint8 *buf[3], *out = NULL;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
|
ret = gst_mpeg2dec_alloc_sized_buf (mpeg2dec, mpeg2dec->size, &outbuf);
|
||||||
size = mpeg2dec->decoded_width * mpeg2dec->decoded_height;
|
if (ret != GST_FLOW_OK)
|
||||||
|
goto no_buffer;
|
||||||
|
|
||||||
ret = gst_mpeg2dec_alloc_sized_buf (mpeg2dec, size * 2, &outbuf);
|
buf[0] = GST_BUFFER_DATA (outbuf);
|
||||||
if (ret != GST_FLOW_OK)
|
buf[1] = buf[0] + mpeg2dec->u_offs;
|
||||||
goto no_buffer;
|
buf[2] = buf[0] + mpeg2dec->v_offs;
|
||||||
|
|
||||||
out = GST_BUFFER_DATA (outbuf);
|
GST_DEBUG_OBJECT (mpeg2dec, "set_buf: %p %p %p, outbuf %p",
|
||||||
|
buf[0], buf[1], buf[2], outbuf);
|
||||||
buf[0] = out;
|
|
||||||
buf[1] = buf[0] + size;
|
|
||||||
buf[2] = buf[1] + size / 2;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
size = I420_SIZE (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
|
|
||||||
ret = gst_mpeg2dec_alloc_sized_buf (mpeg2dec, size, &outbuf);
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto no_buffer;
|
|
||||||
|
|
||||||
out = GST_BUFFER_DATA (outbuf);
|
|
||||||
|
|
||||||
if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
|
|
||||||
buf[0] = out +
|
|
||||||
I420_Y_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
buf[1] = out +
|
|
||||||
I420_U_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
buf[2] = out +
|
|
||||||
I420_V_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
} else {
|
|
||||||
buf[0] = out +
|
|
||||||
I420_Y_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
buf[1] = out +
|
|
||||||
I420_V_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
buf[2] = out +
|
|
||||||
I420_U_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
|
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
|
||||||
|
|
||||||
|
@ -552,6 +492,9 @@ no_buffer:
|
||||||
("Failed to allocate memory for buffer, reason %s",
|
("Failed to allocate memory for buffer, reason %s",
|
||||||
gst_flow_get_name (ret)));
|
gst_flow_get_name (ret)));
|
||||||
}
|
}
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "no output buffer, reason %s",
|
||||||
|
gst_flow_get_name (ret));
|
||||||
|
mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL);
|
||||||
*obuf = NULL;
|
*obuf = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -570,12 +513,27 @@ gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec)
|
||||||
|
|
||||||
if (sequence->width != sequence->chroma_width &&
|
if (sequence->width != sequence->chroma_width &&
|
||||||
sequence->height != sequence->chroma_height) {
|
sequence->height != sequence->chroma_height) {
|
||||||
|
|
||||||
fourcc = GST_STR_FOURCC ("I420");
|
fourcc = GST_STR_FOURCC ("I420");
|
||||||
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
|
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
|
||||||
|
mpeg2dec->size =
|
||||||
|
I420_SIZE (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
||||||
|
|
||||||
|
mpeg2dec->u_offs =
|
||||||
|
I420_U_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
||||||
|
mpeg2dec->v_offs =
|
||||||
|
I420_V_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height);
|
||||||
|
|
||||||
} else if (sequence->width == sequence->chroma_width ||
|
} else if (sequence->width == sequence->chroma_width ||
|
||||||
sequence->height == sequence->chroma_height) {
|
sequence->height == sequence->chroma_height) {
|
||||||
|
gint halfsize;
|
||||||
|
|
||||||
fourcc = GST_STR_FOURCC ("Y42B");
|
fourcc = GST_STR_FOURCC ("Y42B");
|
||||||
mpeg2dec->format = MPEG2DEC_FORMAT_I422;
|
mpeg2dec->format = MPEG2DEC_FORMAT_I422;
|
||||||
|
halfsize = mpeg2dec->decoded_width * mpeg2dec->decoded_height;
|
||||||
|
mpeg2dec->size = halfsize * 2;
|
||||||
|
mpeg2dec->u_offs = halfsize;
|
||||||
|
mpeg2dec->v_offs = halfsize + (halfsize / 2);
|
||||||
} else {
|
} else {
|
||||||
g_warning ("mpeg2dec: 4:4:4 format not yet supported");
|
g_warning ("mpeg2dec: 4:4:4 format not yet supported");
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
|
@ -595,13 +553,21 @@ gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_dummybuf (GstMpeg2dec * mpeg2dec)
|
||||||
|
{
|
||||||
|
g_free (mpeg2dec->dummybuf[0]);
|
||||||
|
|
||||||
|
mpeg2dec->dummybuf[0] = g_malloc (mpeg2dec->size);
|
||||||
|
mpeg2dec->dummybuf[1] = mpeg2dec->dummybuf[0] + mpeg2dec->u_offs;
|
||||||
|
mpeg2dec->dummybuf[2] = mpeg2dec->dummybuf[1] + mpeg2dec->v_offs;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
GstBuffer *buf;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstFlowReturn ret;
|
|
||||||
guint8 *dummybuf[3] = { NULL, NULL, NULL };
|
|
||||||
|
|
||||||
mpeg2dec->width = info->sequence->picture_width;
|
mpeg2dec->width = info->sequence->picture_width;
|
||||||
mpeg2dec->height = info->sequence->picture_height;
|
mpeg2dec->height = info->sequence->picture_height;
|
||||||
|
@ -635,18 +601,14 @@ handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
goto negotiate_failed;
|
goto negotiate_failed;
|
||||||
|
|
||||||
mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
|
mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
|
||||||
|
|
||||||
|
init_dummybuf (mpeg2dec);
|
||||||
|
|
||||||
/* Pump in some null buffers, because otherwise libmpeg2 doesn't
|
/* Pump in some null buffers, because otherwise libmpeg2 doesn't
|
||||||
* initialise the discard_fbuf->id */
|
* initialise the discard_fbuf->id */
|
||||||
mpeg2_set_buf (mpeg2dec->decoder, dummybuf, NULL);
|
mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL);
|
||||||
mpeg2_set_buf (mpeg2dec->decoder, dummybuf, NULL);
|
mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL);
|
||||||
mpeg2_set_buf (mpeg2dec->decoder, dummybuf, NULL);
|
mpeg2_set_buf (mpeg2dec->decoder, mpeg2dec->dummybuf, NULL);
|
||||||
|
|
||||||
ret = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset, &buf);
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* libmpeg2 discards first buffer twice for some reason. */
|
|
||||||
gst_buffer_ref (buf);
|
|
||||||
|
|
||||||
mpeg2dec->need_sequence = FALSE;
|
mpeg2dec->need_sequence = FALSE;
|
||||||
|
|
||||||
|
@ -665,32 +627,67 @@ static GstFlowReturn
|
||||||
handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
{
|
{
|
||||||
gboolean key_frame = FALSE;
|
gboolean key_frame = FALSE;
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf, **bufpen;
|
||||||
|
GstMpeg2Buf *mpbuf;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
gint type;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "handle picture");
|
|
||||||
|
|
||||||
if (info->current_picture) {
|
|
||||||
key_frame =
|
|
||||||
(info->current_picture->flags & PIC_MASK_CODING_TYPE) ==
|
|
||||||
PIC_FLAG_CODING_TYPE_I;
|
|
||||||
}
|
|
||||||
ret = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset, &outbuf);
|
ret = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset, &outbuf);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
goto done;
|
goto no_buffer;
|
||||||
|
|
||||||
|
if (info->current_picture) {
|
||||||
|
type = info->current_picture->flags & PIC_MASK_CODING_TYPE;
|
||||||
|
} else {
|
||||||
|
type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "handle picture type %d", type);
|
||||||
|
|
||||||
|
key_frame = type == PIC_FLAG_CODING_TYPE_I;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PIC_FLAG_CODING_TYPE_I:
|
||||||
|
mpeg2_skip (mpeg2dec->decoder, 0);
|
||||||
|
case PIC_FLAG_CODING_TYPE_P:
|
||||||
|
mpbuf = &mpeg2dec->ip_buffers[mpeg2dec->ip_bufpos];
|
||||||
|
bufpen = &mpbuf->buffer;
|
||||||
|
mpbuf->type = type;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "I/P unref %p, ref %p", *bufpen, outbuf);
|
||||||
|
if (*bufpen)
|
||||||
|
gst_buffer_unref (*bufpen);
|
||||||
|
*bufpen = outbuf;
|
||||||
|
mpeg2dec->ip_bufpos = (mpeg2dec->ip_bufpos + 1) & 3;
|
||||||
|
break;
|
||||||
|
case PIC_FLAG_CODING_TYPE_B:
|
||||||
|
mpbuf = &mpeg2dec->b_buffer;
|
||||||
|
mpbuf->type = type;
|
||||||
|
bufpen = &mpbuf->buffer;
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "B unref %p, ref %p", *bufpen, outbuf);
|
||||||
|
if (*bufpen)
|
||||||
|
gst_buffer_unref (*bufpen);
|
||||||
|
*bufpen = outbuf;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "picture %s, outbuf %p, offset %"
|
GST_DEBUG_OBJECT (mpeg2dec, "picture %s, outbuf %p, offset %"
|
||||||
G_GINT64_FORMAT,
|
G_GINT64_FORMAT,
|
||||||
key_frame ? ", kf," : " ", outbuf, GST_BUFFER_OFFSET (outbuf)
|
key_frame ? ", kf," : " ", outbuf, GST_BUFFER_OFFSET (outbuf)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame)
|
if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame) {
|
||||||
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME;
|
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME;
|
||||||
|
}
|
||||||
|
|
||||||
mpeg2_skip (mpeg2dec->decoder, 0);
|
|
||||||
|
|
||||||
done:
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
no_buffer:
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -698,119 +695,153 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
{
|
{
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
const mpeg2_picture_t *picture;
|
||||||
|
gboolean key_frame = FALSE;
|
||||||
|
GstClockTime time;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "picture slice/end %p %p %p %p",
|
GST_DEBUG_OBJECT (mpeg2dec, "picture slice/end %p %p %p %p",
|
||||||
info->display_fbuf,
|
info->display_fbuf,
|
||||||
info->display_picture, info->current_picture,
|
info->display_picture, info->current_picture,
|
||||||
(info->display_fbuf ? info->display_fbuf->id : NULL));
|
(info->display_fbuf ? info->display_fbuf->id : NULL));
|
||||||
|
|
||||||
if (info->display_fbuf && info->display_fbuf->id) {
|
if (!info->display_fbuf || !info->display_fbuf->id)
|
||||||
const mpeg2_picture_t *picture;
|
goto no_display;
|
||||||
gboolean key_frame = FALSE;
|
|
||||||
GstClockTime time;
|
|
||||||
|
|
||||||
outbuf = GST_BUFFER (info->display_fbuf->id);
|
outbuf = GST_BUFFER (info->display_fbuf->id);
|
||||||
|
|
||||||
picture = info->display_picture;
|
picture = info->display_picture;
|
||||||
|
|
||||||
key_frame =
|
key_frame = (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
|
||||||
(picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "picture keyframe %d", key_frame);
|
GST_DEBUG_OBJECT (mpeg2dec, "picture flags: %d, type: %d, keyframe: %d",
|
||||||
|
picture->flags, picture->flags & PIC_MASK_CODING_TYPE, key_frame);
|
||||||
|
|
||||||
if (!key_frame)
|
if (key_frame) {
|
||||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
else
|
mpeg2_skip (mpeg2dec->decoder, 0);
|
||||||
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
} else {
|
||||||
|
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_KEYFRAME && key_frame)
|
if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_KEYFRAME && key_frame)
|
||||||
mpeg2dec->discont_state = MPEG2DEC_DISC_NONE;
|
mpeg2dec->discont_state = MPEG2DEC_DISC_NONE;
|
||||||
|
|
||||||
time = GST_CLOCK_TIME_NONE;
|
time = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
#if MPEG2_RELEASE < MPEG2_VERSION(0,4,0)
|
#if MPEG2_RELEASE < MPEG2_VERSION(0,4,0)
|
||||||
if (picture->flags & PIC_FLAG_PTS)
|
if (picture->flags & PIC_FLAG_PTS)
|
||||||
time = MPEG_TIME_TO_GST_TIME (picture->pts);
|
time = MPEG_TIME_TO_GST_TIME (picture->pts);
|
||||||
#else
|
#else
|
||||||
if (picture->flags & PIC_FLAG_TAGS)
|
if (picture->flags & PIC_FLAG_TAGS)
|
||||||
time = MPEG_TIME_TO_GST_TIME ((GstClockTime) (picture->
|
time = MPEG_TIME_TO_GST_TIME ((GstClockTime) (picture->
|
||||||
tag2) << 32 | picture->tag);
|
tag2) << 32 | picture->tag);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (time == GST_CLOCK_TIME_NONE) {
|
if (time == GST_CLOCK_TIME_NONE) {
|
||||||
time = mpeg2dec->next_time;
|
time = mpeg2dec->next_time;
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "picture didn't have pts");
|
GST_DEBUG_OBJECT (mpeg2dec, "picture didn't have pts");
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (mpeg2dec,
|
|
||||||
"picture had pts %" GST_TIME_FORMAT ", we had %"
|
|
||||||
GST_TIME_FORMAT, GST_TIME_ARGS (time),
|
|
||||||
GST_TIME_ARGS (mpeg2dec->next_time));
|
|
||||||
mpeg2dec->next_time = time;
|
|
||||||
}
|
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
|
||||||
|
|
||||||
/* TODO set correct offset here based on frame number */
|
|
||||||
if (info->display_picture_2nd) {
|
|
||||||
GST_BUFFER_DURATION (outbuf) = (picture->nb_fields +
|
|
||||||
info->display_picture_2nd->nb_fields) * mpeg2dec->frame_period / 2;
|
|
||||||
} else {
|
|
||||||
GST_BUFFER_DURATION (outbuf) =
|
|
||||||
picture->nb_fields * mpeg2dec->frame_period / 2;
|
|
||||||
}
|
|
||||||
mpeg2dec->next_time += GST_BUFFER_DURATION (outbuf);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec,
|
GST_DEBUG_OBJECT (mpeg2dec,
|
||||||
"picture: %s %s fields:%d off:%" G_GINT64_FORMAT " ts:%"
|
"picture had pts %" GST_TIME_FORMAT ", we had %"
|
||||||
GST_TIME_FORMAT,
|
GST_TIME_FORMAT, GST_TIME_ARGS (time),
|
||||||
(picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
|
GST_TIME_ARGS (mpeg2dec->next_time));
|
||||||
(picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
|
mpeg2dec->next_time = time;
|
||||||
picture->nb_fields, GST_BUFFER_OFFSET (outbuf),
|
}
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
GST_BUFFER_TIMESTAMP (outbuf) = time;
|
||||||
|
|
||||||
if (mpeg2dec->index) {
|
/* TODO set correct offset here based on frame number */
|
||||||
gst_index_add_association (mpeg2dec->index, mpeg2dec->index_id,
|
if (info->display_picture_2nd) {
|
||||||
(key_frame ? GST_ASSOCIATION_FLAG_KEY_UNIT : 0),
|
GST_BUFFER_DURATION (outbuf) = (picture->nb_fields +
|
||||||
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (outbuf),
|
info->display_picture_2nd->nb_fields) * mpeg2dec->frame_period / 2;
|
||||||
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), 0);
|
} else {
|
||||||
}
|
GST_BUFFER_DURATION (outbuf) =
|
||||||
|
picture->nb_fields * mpeg2dec->frame_period / 2;
|
||||||
|
}
|
||||||
|
mpeg2dec->next_time += GST_BUFFER_DURATION (outbuf);
|
||||||
|
|
||||||
if (picture->flags & PIC_FLAG_SKIP) {
|
GST_DEBUG_OBJECT (mpeg2dec,
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
|
"picture: %s %s fields:%d off:%" G_GINT64_FORMAT " ts:%"
|
||||||
} else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) {
|
GST_TIME_FORMAT,
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, discont state %d",
|
(picture->flags & PIC_FLAG_TOP_FIELD_FIRST ? "tff " : " "),
|
||||||
mpeg2dec->discont_state);
|
(picture->flags & PIC_FLAG_PROGRESSIVE_FRAME ? "prog" : " "),
|
||||||
} else if (mpeg2dec->next_time < mpeg2dec->segment_start) {
|
picture->nb_fields, GST_BUFFER_OFFSET (outbuf),
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, next_time %"
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
|
||||||
GST_TIME_FORMAT " < segment_start %" GST_TIME_FORMAT,
|
|
||||||
GST_TIME_ARGS (mpeg2dec->next_time),
|
|
||||||
GST_TIME_ARGS (mpeg2dec->segment_start));
|
|
||||||
} else {
|
|
||||||
gboolean cropped_outbuf_different_from_outbuf = FALSE;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (mpeg2dec, "pushing buffer, timestamp %"
|
if (mpeg2dec->index) {
|
||||||
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
|
gst_index_add_association (mpeg2dec->index, mpeg2dec->index_id,
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
(key_frame ? GST_ASSOCIATION_FLAG_KEY_UNIT : 0),
|
||||||
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
|
GST_FORMAT_BYTES, GST_BUFFER_OFFSET (outbuf),
|
||||||
|
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf), 0);
|
||||||
if ((mpeg2dec->decoded_height > mpeg2dec->height) ||
|
|
||||||
(mpeg2dec->decoded_width > mpeg2dec->width)) {
|
|
||||||
cropped_outbuf_different_from_outbuf = crop_buffer (mpeg2dec, &outbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_buffer_ref (outbuf);
|
|
||||||
ret = gst_pad_push (mpeg2dec->srcpad, outbuf);
|
|
||||||
if (cropped_outbuf_different_from_outbuf)
|
|
||||||
gst_buffer_unref (outbuf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->discard_fbuf && info->discard_fbuf->id) {
|
if (picture->flags & PIC_FLAG_SKIP)
|
||||||
GstBuffer *discard = GST_BUFFER (info->discard_fbuf->id);
|
goto skip;
|
||||||
|
|
||||||
gst_buffer_unref (discard);
|
if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE)
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "Discarded buffer %p", discard);
|
goto drop;
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (time)) {
|
||||||
|
gboolean need_skip;
|
||||||
|
GstClockTime qostime;
|
||||||
|
|
||||||
|
/* qos needs to be done on running time */
|
||||||
|
qostime = gst_segment_to_running_time (&mpeg2dec->segment, GST_FORMAT_TIME,
|
||||||
|
time);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (mpeg2dec);
|
||||||
|
/* check for QoS, don't perform the last steps of getting and
|
||||||
|
* pushing the buffers that are known to be late. */
|
||||||
|
/* FIXME, we can also entirely skip decoding if the next valid buffer is
|
||||||
|
* known to be after a keyframe (using the granule_shift) */
|
||||||
|
need_skip = mpeg2dec->earliest_time != -1
|
||||||
|
&& qostime <= mpeg2dec->earliest_time;
|
||||||
|
GST_OBJECT_UNLOCK (mpeg2dec);
|
||||||
|
|
||||||
|
if (need_skip)
|
||||||
|
goto dropping_qos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mpeg2dec, "pushing buffer %p, timestamp %"
|
||||||
|
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
|
||||||
|
outbuf,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
|
||||||
|
|
||||||
|
if ((mpeg2dec->decoded_height > mpeg2dec->height) ||
|
||||||
|
(mpeg2dec->decoded_width > mpeg2dec->width)) {
|
||||||
|
crop_buffer (mpeg2dec, &outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ref before pushing it out, so we still have the ref in our
|
||||||
|
* array of buffers */
|
||||||
|
gst_buffer_ref (outbuf);
|
||||||
|
ret = gst_pad_push (mpeg2dec->srcpad, outbuf);
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "pushed with result %s", gst_flow_get_name (ret));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* special cases */
|
||||||
|
no_display:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "no picture to display");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
skip:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
drop:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, discont state %d",
|
||||||
|
mpeg2dec->discont_state);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
dropping_qos:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of QoS");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -871,6 +902,27 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
|
|
||||||
mpeg2dec->offset = GST_BUFFER_OFFSET (buf);
|
mpeg2dec->offset = GST_BUFFER_OFFSET (buf);
|
||||||
|
|
||||||
|
if (pts != GST_CLOCK_TIME_NONE) {
|
||||||
|
gint64 mpeg_pts = GST_TIME_TO_MPEG_TIME (pts);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec,
|
||||||
|
"have pts: %" G_GINT64_FORMAT " (%" GST_TIME_FORMAT ")",
|
||||||
|
mpeg_pts, GST_TIME_ARGS (MPEG_TIME_TO_GST_TIME (mpeg_pts)));
|
||||||
|
|
||||||
|
#if MPEG2_RELEASE >= MPEG2_VERSION(0,4,0)
|
||||||
|
mpeg2_tag_picture (mpeg2dec->decoder, mpeg_pts & 0xffffffff,
|
||||||
|
mpeg_pts >> 32);
|
||||||
|
#else
|
||||||
|
mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
GST_LOG ("no pts");
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer");
|
||||||
|
mpeg2_buffer (mpeg2dec->decoder, data, end);
|
||||||
|
GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer done");
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
GST_LOG_OBJECT (mpeg2dec, "calling parse");
|
GST_LOG_OBJECT (mpeg2dec, "calling parse");
|
||||||
state = mpeg2_parse (mpeg2dec->decoder);
|
state = mpeg2_parse (mpeg2dec->decoder);
|
||||||
|
@ -884,6 +936,7 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
|
GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
|
||||||
break;
|
break;
|
||||||
case STATE_GOP:
|
case STATE_GOP:
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "gop");
|
||||||
break;
|
break;
|
||||||
case STATE_PICTURE:
|
case STATE_PICTURE:
|
||||||
ret = handle_picture (mpeg2dec, info);
|
ret = handle_picture (mpeg2dec, info);
|
||||||
|
@ -897,39 +950,16 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
break;
|
break;
|
||||||
#if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
|
#if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
|
||||||
case STATE_INVALID_END:
|
case STATE_INVALID_END:
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "invalid end");
|
||||||
#endif
|
#endif
|
||||||
case STATE_END:
|
case STATE_END:
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "end");
|
||||||
mpeg2dec->need_sequence = TRUE;
|
mpeg2dec->need_sequence = TRUE;
|
||||||
case STATE_SLICE:
|
case STATE_SLICE:
|
||||||
ret = handle_slice (mpeg2dec, info);
|
ret = handle_slice (mpeg2dec, info);
|
||||||
break;
|
break;
|
||||||
case STATE_BUFFER:
|
case STATE_BUFFER:
|
||||||
if (data == NULL) {
|
done = TRUE;
|
||||||
done = TRUE;
|
|
||||||
} else {
|
|
||||||
if (pts != GST_CLOCK_TIME_NONE) {
|
|
||||||
gint64 mpeg_pts = GST_TIME_TO_MPEG_TIME (pts);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec,
|
|
||||||
"have pts: %" G_GINT64_FORMAT " (%" GST_TIME_FORMAT ")",
|
|
||||||
mpeg_pts, GST_TIME_ARGS (MPEG_TIME_TO_GST_TIME (mpeg_pts)));
|
|
||||||
|
|
||||||
#if MPEG2_RELEASE >= MPEG2_VERSION(0,4,0)
|
|
||||||
mpeg2_tag_picture (mpeg2dec->decoder, mpeg_pts & 0xffffffff,
|
|
||||||
mpeg_pts >> 32);
|
|
||||||
#else
|
|
||||||
mpeg2_pts (mpeg2dec->decoder, mpeg_pts);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
GST_LOG ("no pts");
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer");
|
|
||||||
mpeg2_buffer (mpeg2dec->decoder, data, end);
|
|
||||||
GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer done");
|
|
||||||
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
/* error */
|
/* error */
|
||||||
case STATE_INVALID:
|
case STATE_INVALID:
|
||||||
|
@ -962,76 +992,107 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
if (ret != GST_FLOW_OK) {
|
||||||
mpeg2_reset (mpeg2dec->decoder, 0);
|
GST_DEBUG_OBJECT (mpeg2dec, "exit loop, reason %s",
|
||||||
|
gst_flow_get_name (ret));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* errors */
|
||||||
exit:
|
exit:
|
||||||
gst_buffer_unref (buf);
|
{
|
||||||
return GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
exit_error:
|
exit_error:
|
||||||
GST_ELEMENT_ERROR (mpeg2dec, STREAM, DECODE, (NULL), (NULL));
|
{
|
||||||
gst_buffer_unref (buf);
|
GST_ELEMENT_ERROR (mpeg2dec, STREAM, DECODE, (NULL), (NULL));
|
||||||
return GST_FLOW_ERROR;
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
|
gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
GstMpeg2dec *mpeg2dec;
|
||||||
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
|
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
|
mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "Got %s event on sink pad",
|
GST_DEBUG_OBJECT (mpeg2dec, "Got %s event on sink pad",
|
||||||
GST_EVENT_TYPE_NAME (event));
|
GST_EVENT_TYPE_NAME (event));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_NEWSEGMENT:
|
case GST_EVENT_NEWSEGMENT:
|
||||||
{
|
{
|
||||||
mpeg2dec->next_time = -1;;
|
gboolean update;
|
||||||
ret = gst_pad_event_default (pad, event);
|
GstFormat format;
|
||||||
|
gdouble rate, arate;
|
||||||
|
gint64 start, stop, time;
|
||||||
|
|
||||||
|
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
|
||||||
|
&start, &stop, &time);
|
||||||
|
|
||||||
|
/* we need TIME and a positive rate */
|
||||||
|
if (format != GST_FORMAT_TIME)
|
||||||
|
goto newseg_wrong_format;
|
||||||
|
|
||||||
|
if (rate <= 0.0)
|
||||||
|
goto newseg_wrong_rate;
|
||||||
|
|
||||||
|
/* now configure the values */
|
||||||
|
gst_segment_set_newsegment_full (&mpeg2dec->segment, update,
|
||||||
|
rate, arate, format, start, stop, time);
|
||||||
|
|
||||||
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
|
{
|
||||||
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
|
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
|
||||||
mpeg2dec->next_time = -1;;
|
mpeg2dec->next_time = -1;;
|
||||||
|
gst_mpeg2dec_qos_reset (mpeg2dec);
|
||||||
mpeg2_reset (mpeg2dec->decoder, 0);
|
mpeg2_reset (mpeg2dec->decoder, 0);
|
||||||
ret = gst_pad_event_default (pad, event);
|
mpeg2_skip (mpeg2dec->decoder, 1);
|
||||||
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
if (mpeg2dec->index && mpeg2dec->closed) {
|
if (mpeg2dec->index && mpeg2dec->closed) {
|
||||||
gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
|
gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
|
||||||
}
|
}
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = gst_pad_event_default (pad, event);
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
gst_object_unref (mpeg2dec);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
/* ERRORS */
|
||||||
|
newseg_wrong_format:
|
||||||
static GstCaps *
|
{
|
||||||
gst_mpeg2dec_src_getcaps (GstPad * pad)
|
GST_DEBUG_OBJECT (mpeg2dec, "received non TIME newsegment");
|
||||||
{
|
gst_event_unref (event);
|
||||||
GstCaps *caps;
|
goto done;
|
||||||
|
}
|
||||||
GST_OBJECT_LOCK (pad);
|
newseg_wrong_rate:
|
||||||
if (!(caps = GST_PAD_CAPS (pad)))
|
{
|
||||||
caps = (GstCaps *) gst_pad_get_pad_template_caps (pad);
|
GST_DEBUG_OBJECT (mpeg2dec, "negative rates not supported yet");
|
||||||
caps = gst_caps_ref (caps);
|
gst_event_unref (event);
|
||||||
GST_OBJECT_UNLOCK (pad);
|
goto done;
|
||||||
|
}
|
||||||
return caps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -1420,7 +1481,7 @@ gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event)
|
||||||
/* the all-formats seek logic */
|
/* the all-formats seek logic */
|
||||||
case GST_EVENT_SEEK:{
|
case GST_EVENT_SEEK:{
|
||||||
gst_event_ref (event);
|
gst_event_ref (event);
|
||||||
if (!(res = gst_pad_event_default (pad, event))) {
|
if (!(res = gst_pad_push_event (mpeg2dec->sinkpad, event))) {
|
||||||
if (mpeg2dec->index)
|
if (mpeg2dec->index)
|
||||||
res = index_seek (pad, event);
|
res = index_seek (pad, event);
|
||||||
else
|
else
|
||||||
|
@ -1429,6 +1490,26 @@ gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event)
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GST_EVENT_QOS:
|
||||||
|
{
|
||||||
|
gdouble proportion;
|
||||||
|
GstClockTimeDiff diff;
|
||||||
|
GstClockTime timestamp;
|
||||||
|
|
||||||
|
gst_event_parse_qos (event, &proportion, &diff, ×tamp);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (mpeg2dec);
|
||||||
|
mpeg2dec->proportion = proportion;
|
||||||
|
mpeg2dec->earliest_time = timestamp + diff;
|
||||||
|
GST_OBJECT_UNLOCK (mpeg2dec);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec,
|
||||||
|
"got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
|
||||||
|
GST_TIME_ARGS (timestamp), diff);
|
||||||
|
|
||||||
|
res = gst_pad_push_event (mpeg2dec->sinkpad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GST_EVENT_NAVIGATION:
|
case GST_EVENT_NAVIGATION:
|
||||||
/* Forward a navigation event unchanged */
|
/* Forward a navigation event unchanged */
|
||||||
default:
|
default:
|
||||||
|
@ -1460,6 +1541,7 @@ gst_mpeg2dec_change_state (GstElement * element, GstStateChange transition)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
gst_mpeg2dec_reset (mpeg2dec);
|
gst_mpeg2dec_reset (mpeg2dec);
|
||||||
|
gst_mpeg2dec_qos_reset (mpeg2dec);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
default:
|
default:
|
||||||
|
@ -1472,6 +1554,7 @@ gst_mpeg2dec_change_state (GstElement * element, GstStateChange transition)
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
|
gst_mpeg2dec_qos_reset (mpeg2dec);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
if (mpeg2dec->decoder) {
|
if (mpeg2dec->decoder) {
|
||||||
|
|
|
@ -41,8 +41,6 @@ G_BEGIN_DECLS
|
||||||
#define MPEG_TIME_TO_GST_TIME(time) (((time) * (GST_MSECOND/10)) / 9LL)
|
#define MPEG_TIME_TO_GST_TIME(time) (((time) * (GST_MSECOND/10)) / 9LL)
|
||||||
#define GST_TIME_TO_MPEG_TIME(time) (((time) * 9LL) / (GST_MSECOND/10))
|
#define GST_TIME_TO_MPEG_TIME(time) (((time) * 9LL) / (GST_MSECOND/10))
|
||||||
|
|
||||||
#define GST_MPEG2DEC_NUM_BUFS 6
|
|
||||||
|
|
||||||
typedef struct _GstMpeg2dec GstMpeg2dec;
|
typedef struct _GstMpeg2dec GstMpeg2dec;
|
||||||
typedef struct _GstMpeg2decClass GstMpeg2decClass;
|
typedef struct _GstMpeg2decClass GstMpeg2decClass;
|
||||||
|
|
||||||
|
@ -61,6 +59,11 @@ typedef enum
|
||||||
MPEG2DEC_DISC_NEW_KEYFRAME
|
MPEG2DEC_DISC_NEW_KEYFRAME
|
||||||
} DiscontState;
|
} DiscontState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gint type;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
} GstMpeg2Buf;
|
||||||
|
|
||||||
struct _GstMpeg2dec {
|
struct _GstMpeg2dec {
|
||||||
GstElement element;
|
GstElement element;
|
||||||
|
|
||||||
|
@ -75,14 +78,16 @@ struct _GstMpeg2dec {
|
||||||
gboolean closed;
|
gboolean closed;
|
||||||
gboolean have_fbuf;
|
gboolean have_fbuf;
|
||||||
|
|
||||||
GstBuffer *buffers[GST_MPEG2DEC_NUM_BUFS];
|
/* buffer management */
|
||||||
|
guint ip_bufpos;
|
||||||
|
GstMpeg2Buf ip_buffers[4];
|
||||||
|
GstMpeg2Buf b_buffer;
|
||||||
|
|
||||||
DiscontState discont_state;
|
DiscontState discont_state;
|
||||||
|
|
||||||
/* the timestamp of the next frame */
|
/* the timestamp of the next frame */
|
||||||
GstClockTime next_time;
|
GstClockTime next_time;
|
||||||
gint64 segment_start;
|
GstSegment segment;
|
||||||
gint64 segment_end;
|
|
||||||
|
|
||||||
/* video state */
|
/* video state */
|
||||||
Mpeg2decFormat format;
|
Mpeg2decFormat format;
|
||||||
|
@ -95,18 +100,26 @@ struct _GstMpeg2dec {
|
||||||
gint frame_rate_code;
|
gint frame_rate_code;
|
||||||
gint64 total_frames;
|
gint64 total_frames;
|
||||||
gint64 frame_period;
|
gint64 frame_period;
|
||||||
|
|
||||||
|
gint size;
|
||||||
|
gint u_offs;
|
||||||
|
gint v_offs;
|
||||||
|
guint8 *dummybuf[3];
|
||||||
|
|
||||||
|
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
gint fps_n;
|
gint fps_n;
|
||||||
gint fps_d;
|
gint fps_d;
|
||||||
gboolean need_sequence;
|
gboolean need_sequence;
|
||||||
|
|
||||||
GstEvent *pending_event;
|
|
||||||
|
|
||||||
GstIndex *index;
|
GstIndex *index;
|
||||||
gint index_id;
|
gint index_id;
|
||||||
|
|
||||||
gint error_count;
|
gint error_count;
|
||||||
|
|
||||||
|
/* QoS stuff */ /* with LOCK*/
|
||||||
|
gdouble proportion;
|
||||||
|
GstClockTime earliest_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpeg2decClass {
|
struct _GstMpeg2decClass {
|
||||||
|
|
Loading…
Reference in a new issue