ext/mpeg2dec/gstmpeg2dec.*: Removed lots of dubious code.

Original commit message from CVS:
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
(gst_mpeg2dec_dispose), (gst_mpeg2dec_reset),
(gst_mpeg2dec_alloc_buffer), (gst_mpeg2dec_negotiate_format),
(handle_sequence), (handle_picture):
* ext/mpeg2dec/gstmpeg2dec.h:
Removed lots of dubious code.
Handle flushing and seeking correctly. Still leaks though...
This commit is contained in:
Wim Taymans 2005-10-26 16:45:04 +00:00
parent db28f9b3ea
commit 535cd3d2fa
3 changed files with 170 additions and 499 deletions

View file

@ -1,3 +1,13 @@
2005-10-26 Wim Taymans <wim@fluendo.com>
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
(gst_mpeg2dec_dispose), (gst_mpeg2dec_reset),
(gst_mpeg2dec_alloc_buffer), (gst_mpeg2dec_negotiate_format),
(handle_sequence), (handle_picture):
* ext/mpeg2dec/gstmpeg2dec.h:
Removed lots of dubious code.
Handle flushing and seeking correctly. Still leaks though...
2005-10-24 Christian Schaller <christian at fluendo dot com> 2005-10-24 Christian Schaller <christian at fluendo dot com>
* configure.ac: port over thomas plugin listing from base * configure.ac: port over thomas plugin listing from base

View file

@ -187,9 +187,6 @@ static const GstEventMask *gst_mpeg2dec_get_event_masks (GstPad * pad);
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
static GstBuffer *crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input); static GstBuffer *crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input);
static gboolean check_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * buf);
static gboolean free_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * buf);
static void free_all_buffers (GstMpeg2dec * mpeg2dec);
/*static guint gst_mpeg2dec_signals[LAST_SIGNAL] = { 0 };*/ /*static guint gst_mpeg2dec_signals[LAST_SIGNAL] = { 0 };*/
@ -260,8 +257,6 @@ gst_mpeg2dec_class_init (GstMpeg2decClass * klass)
static void static void
gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec) gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
{ {
int i;
/* create the sink and src pads */ /* create the sink and src pads */
mpeg2dec->sinkpad = mpeg2dec->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
@ -293,35 +288,6 @@ gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
#endif #endif
/* initialize the mpeg2dec acceleration */ /* initialize the mpeg2dec acceleration */
mpeg2_accel (MPEG2_ACCEL_DETECT);
mpeg2dec->closed = TRUE;
mpeg2dec->have_fbuf = FALSE;
mpeg2dec->offset = 0;
for (i = 0; i < GST_MPEG2DEC_NUM_BUFS; i++)
mpeg2dec->buffers[i] = NULL;
}
static void
gst_mpeg2dec_close_decoder (GstMpeg2dec * mpeg2dec)
{
if (!mpeg2dec->closed) {
mpeg2_close (mpeg2dec->decoder);
free_all_buffers (mpeg2dec);
mpeg2dec->closed = TRUE;
mpeg2dec->decoder = NULL;
}
}
static void
gst_mpeg2dec_open_decoder (GstMpeg2dec * mpeg2dec)
{
gst_mpeg2dec_close_decoder (mpeg2dec);
mpeg2dec->decoder = mpeg2_init ();
mpeg2dec->closed = FALSE;
mpeg2dec->have_fbuf = FALSE;
mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
} }
static void static void
@ -329,7 +295,11 @@ gst_mpeg2dec_dispose (GObject * object)
{ {
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object); GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (object);
gst_mpeg2dec_close_decoder (mpeg2dec); if (mpeg2dec->decoder) {
GST_DEBUG_OBJECT (mpeg2dec, "closing decoder");
mpeg2_close (mpeg2dec->decoder);
mpeg2dec->decoder = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
@ -345,10 +315,11 @@ gst_mpeg2dec_reset (GstMpeg2dec * mpeg2dec)
mpeg2dec->segment_end = -1; 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;
gst_pad_use_fixed_caps (mpeg2dec->srcpad);
gst_mpeg2dec_open_decoder (mpeg2dec);
mpeg2dec->need_sequence = TRUE; mpeg2dec->need_sequence = TRUE;
mpeg2dec->next_time = 0;
mpeg2dec->offset = 0;
} }
static void static void
gst_mpeg2dec_set_index (GstElement * element, GstIndex * index) gst_mpeg2dec_set_index (GstElement * element, GstIndex * index)
{ {
@ -367,65 +338,6 @@ gst_mpeg2dec_get_index (GstElement * element)
return mpeg2dec->index; return mpeg2dec->index;
} }
static gboolean
put_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * buf)
{
int i;
for (i = 0; i < GST_MPEG2DEC_NUM_BUFS; i++) {
if (mpeg2dec->buffers[i] == NULL) {
GST_DEBUG_OBJECT (mpeg2dec, "Placing %p at slot %d", buf, i);
mpeg2dec->buffers[i] = buf;
return TRUE;
}
}
return FALSE;
}
static gboolean
check_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * buf)
{
int i;
for (i = 0; i < GST_MPEG2DEC_NUM_BUFS; i++)
if (mpeg2dec->buffers[i] == buf)
return TRUE;
return FALSE;
}
static gboolean
free_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * buf)
{
int i;
for (i = 0; i < GST_MPEG2DEC_NUM_BUFS; i++) {
if (mpeg2dec->buffers[i] == buf) {
GST_DEBUG_OBJECT (mpeg2dec, "Releasing %p at slot %d", buf, i);
gst_buffer_unref (buf);
mpeg2dec->buffers[i] = NULL;
return TRUE;
}
}
return FALSE;
}
static void
free_all_buffers (GstMpeg2dec * mpeg2dec)
{
int i;
for (i = 0; i < GST_MPEG2DEC_NUM_BUFS; i++) {
if (mpeg2dec->buffers[i] != NULL) {
GST_DEBUG_OBJECT (mpeg2dec, "free_all Releasing %p at slot %d",
mpeg2dec->buffers[i], i);
gst_buffer_unref (mpeg2dec->buffers[i]);
mpeg2dec->buffers[i] = NULL;
}
}
}
static GstBuffer * static GstBuffer *
crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input) crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input)
{ {
@ -504,85 +416,52 @@ gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, gint64 offset)
guint8 *buf[3], *out = NULL; guint8 *buf[3], *out = NULL;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
do { if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
ret =
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
size * 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("Failed to allocate memory for buffer"));
goto done;
}
out = GST_BUFFER_DATA (outbuf);
if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) { buf[0] = out;
ret = buf[1] = buf[0] + size;
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE, buf[2] = buf[1] + size / 2;
size * 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("Failed to allocate memory for buffer"));
break;
}
/* 0.9
outbuf =
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
size * 2);
if (!outbuf) { } else {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL), ret =
("Failed to allocate memory for buffer")); gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
return NULL; (size * 3) / 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
} if (ret != GST_FLOW_OK) {
*/ GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("Failed to allocate memory for buffer"));
goto done;
}
out = GST_BUFFER_DATA (outbuf); out = GST_BUFFER_DATA (outbuf);
buf[0] = out;
if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) {
buf[0] = out; buf[0] = out;
buf[1] = buf[0] + size; buf[1] = buf[0] + size;
buf[2] = buf[1] + size / 2; buf[2] = buf[1] + size / 4;
} else { } else {
/* 0.9
outbuf =
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
(size * 3) / 2);
*/
ret =
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
size * 2, GST_PAD_CAPS (mpeg2dec->srcpad), &outbuf);
if (ret != GST_FLOW_OK) {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("Failed to allocate memory for buffer"));
break;
}
out = GST_BUFFER_DATA (outbuf);
buf[0] = out; buf[0] = out;
if (mpeg2dec->format == MPEG2DEC_FORMAT_I420) { buf[2] = buf[0] + size;
buf[0] = out; buf[1] = buf[2] + size / 4;
buf[1] = buf[0] + size;
buf[2] = buf[1] + size / 4;
} else {
buf[0] = out;
buf[2] = buf[0] + size;
buf[1] = buf[2] + size / 4;
}
} }
if (!put_buffer (mpeg2dec, outbuf)) {
#if 0
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("No free slot. libmpeg2 did not discard buffers."));
#else
GST_WARNING_OBJECT (mpeg2dec,
"No free slot. libmpeg2 did not discard buffers.");
#endif
return NULL;
}
mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
/* we store the original byteoffset of this picture in the stream here
* because we need it for indexing */
GST_BUFFER_OFFSET (outbuf) = offset;
} }
while (FALSE);
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
/* we store the original byteoffset of this picture in the stream here
* because we need it for indexing */
GST_BUFFER_OFFSET (outbuf) = offset;
done:
if (ret != GST_FLOW_OK) { if (ret != GST_FLOW_OK) {
outbuf = NULL; /* just to asure NULL return, looking the path outbuf = NULL; /* just to asure NULL return, looking the path
above it happens only when gst_pad_alloc_buffer above it happens only when gst_pad_alloc_buffer
@ -596,54 +475,36 @@ static gboolean
gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec) gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec)
{ {
GstCaps *caps; GstCaps *caps;
guint32 fourcc, myFourcc; guint32 fourcc;
gboolean ret = TRUE;
const mpeg2_info_t *info; const mpeg2_info_t *info;
const mpeg2_sequence_t *sequence; const mpeg2_sequence_t *sequence;
if (!GST_PAD_IS_LINKED (mpeg2dec->srcpad)) {
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
return TRUE;
}
info = mpeg2_info (mpeg2dec->decoder); info = mpeg2_info (mpeg2dec->decoder);
sequence = info->sequence; sequence = info->sequence;
if (sequence->width != sequence->chroma_width && if (sequence->width != sequence->chroma_width &&
sequence->height != sequence->chroma_height) sequence->height != sequence->chroma_height) {
myFourcc = GST_STR_FOURCC ("I420"); fourcc = GST_STR_FOURCC ("I420");
else if (sequence->width == sequence->chroma_width || mpeg2dec->format = MPEG2DEC_FORMAT_I420;
sequence->height == sequence->chroma_height) } else if (sequence->width == sequence->chroma_width ||
myFourcc = GST_STR_FOURCC ("Y42B"); sequence->height == sequence->chroma_height) {
else { fourcc = GST_STR_FOURCC ("Y42B");
mpeg2dec->format = MPEG2DEC_FORMAT_I422;
} 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);
} }
caps = gst_caps_new_simple ("video/x-raw-yuv", caps = gst_caps_new_simple ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, myFourcc, "format", GST_TYPE_FOURCC, fourcc,
"width", G_TYPE_INT, mpeg2dec->width, "width", G_TYPE_INT, mpeg2dec->width,
"height", G_TYPE_INT, mpeg2dec->height, "height", G_TYPE_INT, mpeg2dec->height,
"pixel-aspect-ratio", GST_TYPE_FRACTION, mpeg2dec->pixel_width, "pixel-aspect-ratio", GST_TYPE_FRACTION, mpeg2dec->pixel_width,
mpeg2dec->pixel_height, mpeg2dec->pixel_height,
"framerate", G_TYPE_DOUBLE, mpeg2dec->frame_rate, NULL); "framerate", G_TYPE_DOUBLE, mpeg2dec->frame_rate, NULL);
// ret = gst_pad_set_explicit_caps (mpeg2dec->srcpad, caps); gst_pad_set_caps (mpeg2dec->srcpad, caps);
ret = gst_pad_set_caps (mpeg2dec->srcpad, caps); gst_caps_unref (caps);
if (!ret)
return FALSE;
/* it worked, try to find what it was again */
gst_structure_get_fourcc (gst_caps_get_structure (caps, 0),
"format", &fourcc);
if (fourcc == GST_STR_FOURCC ("Y42B")) {
mpeg2dec->format = MPEG2DEC_FORMAT_I422;
} else if (fourcc == GST_STR_FOURCC ("I420")) {
mpeg2dec->format = MPEG2DEC_FORMAT_I420;
} else {
mpeg2dec->format = MPEG2DEC_FORMAT_YV12;
}
return TRUE; return TRUE;
} }
@ -679,20 +540,23 @@ handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
info->sequence->transfer_characteristics, info->sequence->transfer_characteristics,
info->sequence->matrix_coefficients); info->sequence->matrix_coefficients);
if (!gst_mpeg2dec_negotiate_format (mpeg2dec)) { if (!gst_mpeg2dec_negotiate_format (mpeg2dec))
GST_ELEMENT_ERROR (mpeg2dec, CORE, NEGOTIATION, (NULL), (NULL)); goto negotiate_failed;
return FALSE;
}
free_all_buffers (mpeg2dec); mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
if (!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset) ||
!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset) || if (!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset))
!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset))
return FALSE; return FALSE;
mpeg2dec->need_sequence = FALSE; mpeg2dec->need_sequence = FALSE;
return TRUE; return TRUE;
negotiate_failed:
{
GST_ELEMENT_ERROR (mpeg2dec, CORE, NEGOTIATION, (NULL), (NULL));
return FALSE;
}
} }
static gboolean static gboolean
@ -701,6 +565,8 @@ handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
gboolean key_frame = FALSE; gboolean key_frame = FALSE;
GstBuffer *outbuf; GstBuffer *outbuf;
GST_DEBUG_OBJECT (mpeg2dec, "handle picture");
if (info->current_picture) { if (info->current_picture) {
key_frame = key_frame =
(info->current_picture->flags & PIC_MASK_CODING_TYPE) == (info->current_picture->flags & PIC_MASK_CODING_TYPE) ==
@ -718,10 +584,7 @@ handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
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;
if (!GST_PAD_IS_USABLE (mpeg2dec->srcpad)) mpeg2_skip (mpeg2dec->decoder, 0);
mpeg2_skip (mpeg2dec->decoder, 1);
else
mpeg2_skip (mpeg2dec->decoder, 0);
return TRUE; return TRUE;
} }
@ -743,13 +606,6 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
gboolean key_frame = FALSE; gboolean key_frame = FALSE;
outbuf = GST_BUFFER (info->display_fbuf->id); outbuf = GST_BUFFER (info->display_fbuf->id);
if (!check_buffer (mpeg2dec, outbuf)) {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("libmpeg2 reported invalid buffer %p", outbuf));
return FALSE;
}
gst_buffer_ref (outbuf);
picture = info->display_picture; picture = info->display_picture;
@ -813,8 +669,7 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
if (picture->flags & PIC_FLAG_SKIP) { if (picture->flags & PIC_FLAG_SKIP) {
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag"); GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of skip flag");
gst_buffer_unref (outbuf); gst_buffer_unref (outbuf);
} else if (!GST_PAD_IS_USABLE (mpeg2dec->srcpad) } else if (gst_pad_get_negotiated_caps (mpeg2dec->srcpad) == NULL) {
|| gst_pad_get_negotiated_caps (mpeg2dec->srcpad) == NULL) {
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, pad not usable"); GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, pad not usable");
gst_buffer_unref (outbuf); gst_buffer_unref (outbuf);
} else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) { } else if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) {
@ -857,14 +712,7 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
} }
if (info->discard_fbuf && info->discard_fbuf->id) { if (info->discard_fbuf && info->discard_fbuf->id) {
if (free_buffer (mpeg2dec, GST_BUFFER (info->discard_fbuf->id))) { GST_DEBUG_OBJECT (mpeg2dec, "Discarded buffer %p", info->discard_fbuf->id);
GST_DEBUG_OBJECT (mpeg2dec, "Discarded buffer %p",
info->discard_fbuf->id);
} else {
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("libmpeg2 reported invalid buffer %p", info->discard_fbuf->id));
}
} }
return TRUE; return TRUE;
} }
@ -899,79 +747,10 @@ update_streaminfo (GstMpeg2dec * mpeg2dec)
} }
#endif #endif
static void
gst_mpeg2dec_flush_decoder (GstMpeg2dec * mpeg2dec)
{
if (mpeg2dec->decoder) {
const mpeg2_info_t *info = mpeg2_info (mpeg2dec->decoder);
mpeg2_state_t state;
/*
* iterate the decoder and free buffers
*/
do {
state = mpeg2_parse (mpeg2dec->decoder);
switch (state) {
case STATE_SEQUENCE:
if (!handle_sequence (mpeg2dec, info)) {
gst_mpeg2dec_close_decoder (mpeg2dec);
gst_mpeg2dec_open_decoder (mpeg2dec);
state = -1;
}
break;
case STATE_PICTURE:
if (!handle_picture (mpeg2dec, info)) {
gst_mpeg2dec_close_decoder (mpeg2dec);
gst_mpeg2dec_open_decoder (mpeg2dec);
state = -1;
break;
}
mpeg2_skip (mpeg2dec->decoder, 1);
break;
case STATE_END:
#if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
case STATE_INVALID_END:
#endif
case STATE_SLICE:
if (info->discard_fbuf) {
if (free_buffer (mpeg2dec, GST_BUFFER (info->discard_fbuf->id))) {
GST_DEBUG_OBJECT (mpeg2dec, "Discarded buffer %p",
info->discard_fbuf->id);
} else {
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("libmpeg2 reported invalid buffer %p, fbuf: %p",
info->discard_fbuf->id, info->discard_fbuf));
}
}
break;
case STATE_INVALID:
GST_WARNING_OBJECT (mpeg2dec, "Decoding error");
/*
* We need to close the decoder here, according to docs
*/
gst_mpeg2dec_close_decoder (mpeg2dec);
gst_mpeg2dec_open_decoder (mpeg2dec);
return;
default:
break;
}
}
while (state != STATE_BUFFER && state != -1);
#if MPEG2_RELEASE >= MPEG2_VERSION(0,4,0)
GST_DEBUG_OBJECT (mpeg2dec, "resetting mpeg2 stream decoder");
/* 0 starts at next picture, 1 at next sequence header */
mpeg2_reset (mpeg2dec->decoder, 0);
#endif
}
}
static GstFlowReturn static GstFlowReturn
gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf) gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
{ {
/* 0.9 GstBuffer *buf = GST_BUFFER (_data); */ GstMpeg2dec *mpeg2dec;
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
guint32 size; guint32 size;
guint8 *data, *end; guint8 *data, *end;
GstClockTime pts; GstClockTime pts;
@ -979,73 +758,39 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
mpeg2_state_t state; mpeg2_state_t state;
gboolean done = FALSE; gboolean done = FALSE;
mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
size = GST_BUFFER_SIZE (buf); size = GST_BUFFER_SIZE (buf);
data = GST_BUFFER_DATA (buf); data = GST_BUFFER_DATA (buf);
pts = GST_BUFFER_TIMESTAMP (buf); pts = GST_BUFFER_TIMESTAMP (buf);
GST_LOG_OBJECT (mpeg2dec, "received buffer, timestamp %" GST_LOG_OBJECT (mpeg2dec, "received buffer, timestamp %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
info = mpeg2_info (mpeg2dec->decoder); info = mpeg2dec->info;
end = data + size; end = data + size;
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");
mpeg2dec->offset = GST_BUFFER_OFFSET (buf); mpeg2dec->offset = GST_BUFFER_OFFSET (buf);
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);
GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state); GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state);
switch (state) { switch (state) {
case STATE_SEQUENCE: case STATE_SEQUENCE:
if (!handle_sequence (mpeg2dec, info)) { handle_sequence (mpeg2dec, info);
goto exit;
}
if (mpeg2dec->pending_event) {
done = TRUE;
#if 0
GST_EVENT_SEEK_FLAGS (mpeg2dec->pending_event) & GST_SEEK_FLAG_FLUSH;
#endif
gst_mpeg2dec_src_event (mpeg2dec->srcpad, mpeg2dec->pending_event);
mpeg2dec->pending_event = NULL;
}
break; break;
case STATE_SEQUENCE_REPEATED: case STATE_SEQUENCE_REPEATED:
GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated"); GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
break;
case STATE_GOP: case STATE_GOP:
break; break;
case STATE_PICTURE: case STATE_PICTURE:
{ handle_picture (mpeg2dec, info);
if (!handle_picture (mpeg2dec, info)) {
goto exit;
}
break; break;
}
case STATE_SLICE_1ST: case STATE_SLICE_1ST:
GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered"); GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered");
break; break;
@ -1059,25 +804,42 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
case STATE_END: case STATE_END:
mpeg2dec->need_sequence = TRUE; mpeg2dec->need_sequence = TRUE;
case STATE_SLICE: case STATE_SLICE:
if (!handle_slice (mpeg2dec, info)) { handle_slice (mpeg2dec, info);
goto exit;
}
break; break;
case STATE_BUFFER: case STATE_BUFFER:
case -1: if (data == NULL) {
/* need more data */ 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:
GST_WARNING_OBJECT (mpeg2dec, "Decoding error"); GST_WARNING_OBJECT (mpeg2dec, "Decoding error");
goto exit; goto exit;
break;
default: default:
GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state); GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state);
break; break;
} }
@ -1086,13 +848,11 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
*/ */
#ifdef enable_user_data #ifdef enable_user_data
if (info->user_data_len > 0) { if (info->user_data_len > 0) {
if (GST_PAD_IS_USABLE (mpeg2dec->userdatapad)) { GstBuffer *udbuf = gst_buffer_new_and_alloc (info->user_data_len);
GstBuffer *udbuf = gst_buffer_new_and_alloc (info->user_data_len);
memcpy (GST_BUFFER_DATA (udbuf), info->user_data, info->user_data_len); memcpy (GST_BUFFER_DATA (udbuf), info->user_data, info->user_data_len);
gst_pad_push (mpeg2dec->userdatapad, GST_BUFFER (udbuf)); gst_pad_push (mpeg2dec->userdatapad, udbuf);
}
} }
#endif #endif
@ -1101,12 +861,6 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
return GST_FLOW_OK; return GST_FLOW_OK;
exit: exit:
/*
* Close and reopen the decoder, because
* something went pretty wrong
*/
gst_mpeg2dec_close_decoder (mpeg2dec);
gst_mpeg2dec_open_decoder (mpeg2dec);
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -1121,45 +875,8 @@ gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT: case GST_EVENT_NEWSEGMENT:
{ {
#if 0
gint64 time;
gint64 end_time; /* 0.9 just to call
gst_event_discont_get_value, non
used anywhere else */
#endif
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
#if 0
if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &time,
&end_time)
|| !GST_CLOCK_TIME_IS_VALID (time)) {
GST_WARNING_OBJECT (mpeg2dec,
"No new time offset in discont event %p", event);
} else {
mpeg2dec->next_time = time;
GST_DEBUG_OBJECT (mpeg2dec,
"discont, reset next_time to %" G_GUINT64_FORMAT " (%"
GST_TIME_FORMAT ")", mpeg2dec->next_time,
GST_TIME_ARGS (mpeg2dec->next_time));
}
#endif
// what's hell is that
/*
if (GST_EVENT_DISCONT_NEW_MEDIA (event))
{
gst_mpeg2dec_reset (mpeg2dec);
}
else
{
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
gst_mpeg2dec_flush_decoder (mpeg2dec);
}
*/
mpeg2dec->next_time = -1;; mpeg2dec->next_time = -1;;
ret = gst_pad_event_default (pad, event); ret = gst_pad_event_default (pad, event);
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
@ -1170,7 +887,8 @@ gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP:
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE; mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
gst_mpeg2dec_flush_decoder (mpeg2dec); mpeg2dec->next_time = -1;;
mpeg2_reset (mpeg2dec->decoder, 0);
ret = gst_pad_event_default (pad, event); ret = gst_pad_event_default (pad, event);
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
break; break;
@ -1194,29 +912,6 @@ gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
} }
#if 0
static const GstFormat *
gst_mpeg2dec_get_formats (GstPad * pad)
{
static GstFormat src_formats[] = {
GST_FORMAT_BYTES,
GST_FORMAT_TIME,
GST_FORMAT_DEFAULT,
0
};
static GstFormat sink_formats[] = {
GST_FORMAT_BYTES,
GST_FORMAT_TIME,
0
};
return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
}
#endif
static GstCaps * static GstCaps *
gst_mpeg2dec_src_getcaps (GstPad * pad) gst_mpeg2dec_src_getcaps (GstPad * pad)
{ {
@ -1372,13 +1067,9 @@ gst_mpeg2dec_src_query (GstPad * pad, GstQuery * query)
gst_query_parse_position (query, &format, NULL); gst_query_parse_position (query, &format, NULL);
/* and convert to the requested format */ /* and convert to the requested format */
if (format != GST_FORMAT_DEFAULT) { if (!gst_mpeg2dec_src_convert (pad, GST_FORMAT_TIME,
if (!gst_mpeg2dec_src_convert (pad, GST_FORMAT_DEFAULT, mpeg2dec->next_time, &format, &cur))
mpeg2dec->next_time, &format, &cur)) goto error;
goto error;
} else {
cur = mpeg2dec->next_time;
}
gst_query_set_position (query, format, cur); gst_query_set_position (query, format, cur);
@ -1393,41 +1084,39 @@ gst_mpeg2dec_src_query (GstPad * pad, GstQuery * query)
gint64 total, total_bytes; gint64 total, total_bytes;
GstPad *peer; GstPad *peer;
if ((peer = gst_pad_get_peer (mpeg2dec->sinkpad)) == NULL)
goto error;
/* send to peer */
if ((res = gst_pad_query (peer, query))) {
gst_object_unref (peer);
goto done;
} else {
GST_LOG_OBJECT (mpeg2dec, "query on peer pad failed, trying bytes");
}
/* save requested format */ /* save requested format */
gst_query_parse_duration (query, &format, NULL); gst_query_parse_duration (query, &format, NULL);
/* query peer for total length in bytes */ /* query peer for total length in bytes */
gst_query_set_duration (query, GST_FORMAT_BYTES, -1); gst_query_set_duration (query, GST_FORMAT_BYTES, -1);
if ((peer = gst_pad_get_peer (mpeg2dec->sinkpad)) == NULL) if (!(res = gst_pad_query (peer, query))) {
goto error;
if (!gst_pad_query (peer, query)) {
GST_LOG_OBJECT (mpeg2dec, "query on peer pad failed"); GST_LOG_OBJECT (mpeg2dec, "query on peer pad failed");
gst_object_unref (peer);
goto error; goto error;
} }
gst_object_unref (peer); gst_object_unref (peer);
/* get the returned format */ /* get the returned format */
gst_query_parse_duration (query, &rformat, &total_bytes); gst_query_parse_duration (query, &rformat, &total_bytes);
if (rformat == GST_FORMAT_BYTES) GST_LOG_OBJECT (mpeg2dec, "peer pad returned total=%lld bytes",
GST_LOG_OBJECT (mpeg2dec, "peer pad returned total=%lld bytes", total_bytes);
total_bytes);
else if (rformat == GST_FORMAT_TIME)
GST_LOG_OBJECT (mpeg2dec, "peer pad returned time=%lld", total_bytes);
/* Check if requested format is returned format */
if (format == rformat)
return TRUE;
if (total_bytes != -1) { if (total_bytes != -1) {
if (format != GST_FORMAT_BYTES) { if (!gst_mpeg2dec_sink_convert (pad, GST_FORMAT_BYTES, total_bytes,
if (!gst_mpeg2dec_sink_convert (pad, GST_FORMAT_BYTES, total_bytes, &format, &total))
&format, &total)) goto error;
goto error;
} else {
total = total_bytes;
}
} else { } else {
total = -1; total = -1;
} }
@ -1442,6 +1131,7 @@ gst_mpeg2dec_src_query (GstPad * pad, GstQuery * query)
res = FALSE; res = FALSE;
break; break;
} }
done:
return res; return res;
error: error:
@ -1597,44 +1287,6 @@ normal_seek (GstPad * pad, GstEvent * event)
/* do the seek */ /* do the seek */
res = gst_pad_push_event (mpeg2dec->sinkpad, seek_event); res = gst_pad_push_event (mpeg2dec->sinkpad, seek_event);
} }
#if 0
/* get our peer formats */
if (GST_PAD_PEER (mpeg2dec->sinkpad))
peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad));
/* while we did not exhaust our seek formats without result */
while (peer_formats && *peer_formats) {
gint64 desired_offset;
format = *peer_formats;
/* try to convert requested format to one we can seek with on the sinkpad */
if (gst_mpeg2dec_sink_convert (mpeg2dec->sinkpad, GST_FORMAT_TIME,
src_offset, &format, &desired_offset)) {
GstEvent *seek_event;
/* conversion succeeded, create the seek */
seek_event =
gst_event_new_seek (format | GST_SEEK_METHOD_SET | flush,
desired_offset);
/* do the seekk */
if (gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), seek_event)) {
/* seek worked, we're done, loop will exit */
res = TRUE;
break;
}
}
peer_formats++;
}
/* at this point, either the seek worked and res = TRUE or res == FALSE and the seek
* failed */
if (res && flush) {
/* if we need to flush, iterate until the buffer is empty */
gst_mpeg2dec_flush_decoder (mpeg2dec);
}
#endif
return res; return res;
/* ERRORS */ /* ERRORS */
@ -1650,7 +1302,7 @@ convert_failed:
static gboolean static gboolean
gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event) gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event)
{ {
gboolean res = TRUE; gboolean res;
GstMpeg2dec *mpeg2dec; GstMpeg2dec *mpeg2dec;
mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad)); mpeg2dec = GST_MPEG2DEC (GST_PAD_PARENT (pad));
@ -1661,27 +1313,19 @@ gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
/* the all-formats seek logic */ /* the all-formats seek logic */
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
if (mpeg2dec->need_sequence) { if (mpeg2dec->index)
mpeg2dec->pending_event = event; res = index_seek (pad, event);
return TRUE; else
} else { res = normal_seek (pad, event);
if (mpeg2dec->index)
res = index_seek (pad, event);
else
res = normal_seek (pad, event);
if (res) gst_event_unref (event);
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
}
break; break;
case GST_EVENT_NAVIGATION: case GST_EVENT_NAVIGATION:
/* Forward a navigation event unchanged */ /* Forward a navigation event unchanged */
return gst_pad_push_event (mpeg2dec->sinkpad, event);
default: default:
res = FALSE; res = gst_pad_push_event (mpeg2dec->sinkpad, event);
break; break;
} }
gst_event_unref (event);
return res; return res;
} }
@ -1693,9 +1337,12 @@ gst_mpeg2dec_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
mpeg2_accel (MPEG2_ACCEL_DETECT);
if ((mpeg2dec->decoder = mpeg2_init ()) == NULL)
goto init_failed;
mpeg2dec->info = mpeg2_info (mpeg2dec->decoder);
break; break;
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
mpeg2dec->next_time = 0;
gst_mpeg2dec_reset (mpeg2dec); gst_mpeg2dec_reset (mpeg2dec);
break; break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
@ -1709,14 +1356,26 @@ 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_close_decoder (mpeg2dec);
break; break;
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:
if (mpeg2dec->decoder) {
mpeg2_close (mpeg2dec->decoder);
mpeg2dec->decoder = NULL;
mpeg2dec->info = NULL;
}
break; break;
default: default:
break; break;
} }
return ret; return ret;
/* ERRORS */
init_failed:
{
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, INIT,
(NULL), ("Failed to initialize libmpeg2 library"));
return GST_STATE_CHANGE_FAILURE;
}
} }
static void static void

View file

@ -70,6 +70,8 @@ struct _GstMpeg2dec {
*userdatapad; *userdatapad;
mpeg2dec_t *decoder; mpeg2dec_t *decoder;
const mpeg2_info_t *info;
gboolean closed; gboolean closed;
gboolean have_fbuf; gboolean have_fbuf;