ext/mpeg2dec/gstmpeg2dec.*: Rearrange buffer tracking and refcounting and refactor a little for readability.

Original commit message from CVS:
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
(gst_mpeg2dec_close_decoder), (put_buffer), (check_buffer),
(free_buffer), (free_all_buffers), (gst_mpeg2dec_alloc_buffer),
(handle_sequence), (handle_picture):
* ext/mpeg2dec/gstmpeg2dec.h:
Rearrange buffer tracking and refcounting and refactor
a little for readability.
This commit is contained in:
Jan Schmidt 2005-02-04 13:43:28 +00:00
parent fa1ca2804c
commit 74ea3b6d3c
3 changed files with 372 additions and 210 deletions

View file

@ -1,3 +1,13 @@
2005-02-05 Jan Schmidt <thaytan@mad.scientist.com>
* ext/mpeg2dec/gstmpeg2dec.c: (gst_mpeg2dec_init),
(gst_mpeg2dec_close_decoder), (put_buffer), (check_buffer),
(free_buffer), (free_all_buffers), (gst_mpeg2dec_alloc_buffer),
(handle_sequence), (handle_picture):
* ext/mpeg2dec/gstmpeg2dec.h:
Rearrange buffer tracking and refcounting and refactor
a little for readability.
2005-02-04 Jan Schmidt <thaytan@mad.scientist.com>
* sys/v4l/gstv4l.c: (plugin_init):
* sys/v4l/gstv4ljpegsrc.c: (gst_v4ljpegsrc_get_type),

View file

@ -177,6 +177,9 @@ static void gst_mpeg2dec_chain (GstPad * pad, GstData * _data);
static GstElementClass *parent_class = NULL;
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 };*/
@ -247,6 +250,8 @@ gst_mpeg2dec_class_init (GstMpeg2decClass * klass)
static void
gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
{
int i;
/* create the sink and src pads */
mpeg2dec->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
@ -286,6 +291,10 @@ gst_mpeg2dec_init (GstMpeg2dec * mpeg2dec)
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;
GST_FLAG_SET (GST_ELEMENT (mpeg2dec), GST_ELEMENT_EVENT_AWARE);
}
@ -295,6 +304,7 @@ gst_mpeg2dec_close_decoder (GstMpeg2dec * mpeg2dec)
{
if (!mpeg2dec->closed) {
mpeg2_close (mpeg2dec->decoder);
free_all_buffers (mpeg2dec);
mpeg2dec->closed = TRUE;
mpeg2dec->decoder = NULL;
}
@ -337,6 +347,62 @@ gst_mpeg2dec_get_index (GstElement * element)
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_buffer_unref (mpeg2dec->buffers[i]);
mpeg2dec->buffers[i] = NULL;
}
}
}
static GstBuffer *
crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input)
@ -408,21 +474,24 @@ crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input)
return outbuf;
}
static GstBuffer *
gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info,
gint64 offset)
gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, gint64 offset)
{
GstBuffer *outbuf = NULL;
gint size = mpeg2dec->decoded_width * mpeg2dec->decoded_height;
guint8 *buf[3], *out;
const mpeg2_picture_t *picture;
if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
outbuf =
gst_pad_alloc_buffer (mpeg2dec->srcpad, GST_BUFFER_OFFSET_NONE,
size * 2);
if (!outbuf) {
GST_ELEMENT_ERROR (mpeg2dec, RESOURCE, FAILED, (NULL),
("Failed to allocate memory for buffer"));
return NULL;
}
out = GST_BUFFER_DATA (outbuf);
buf[0] = out;
@ -448,19 +517,15 @@ gst_mpeg2dec_alloc_buffer (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info,
}
}
gst_buffer_ref (outbuf);
if (!put_buffer (mpeg2dec, outbuf)) {
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("No free slot. libmpeg2 did not discard buffers."));
return NULL;
}
mpeg2_custom_fbuf (mpeg2dec->decoder, 1);
mpeg2_set_buf (mpeg2dec->decoder, buf, outbuf);
picture = info->current_picture;
if (picture
&& (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
} else {
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_KEY_UNIT);
}
/* we store the original byteoffset of this picture in the stream here
* because we need it for indexing */
GST_BUFFER_OFFSET (outbuf) = offset;
@ -523,150 +588,8 @@ gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec)
return TRUE;
}
#if 0
static void
update_streaminfo (GstMpeg2dec * mpeg2dec)
{
GstCaps *caps;
GstProps *props;
GstPropsEntry *entry;
const mpeg2_info_t *info;
info = mpeg2_info (mpeg2dec->decoder);
props = gst_props_empty_new ();
entry =
gst_props_entry_new ("framerate",
G_TYPE_DOUBLE (GST_SECOND / (float) mpeg2dec->frame_period));
gst_props_add_entry (props, entry);
entry =
gst_props_entry_new ("bitrate",
G_TYPE_INT (info->sequence->byte_rate * 8));
gst_props_add_entry (props, entry);
caps = gst_caps_new ("mpeg2dec_streaminfo",
"application/x-gst-streaminfo", props);
gst_caps_replace_sink (&mpeg2dec->streaminfo, caps);
g_object_notify (G_OBJECT (mpeg2dec), "streaminfo");
}
#endif
static void
gst_mpeg2dec_flush_decoder (GstMpeg2dec * mpeg2dec)
{
if (mpeg2dec->decoder) {
#if MPEG2_RELEASE < MPEG2_VERSION(0,4,0)
const mpeg2_info_t *info = mpeg2_info (mpeg2dec->decoder);
mpeg2_state_t state;
do {
state = mpeg2_parse (mpeg2dec->decoder);
if (state == STATE_END) {
if (info->discard_fbuf && info->discard_fbuf->id) {
gst_buffer_unref ((GstBuffer *) info->discard_fbuf->id);
}
}
}
while (state != STATE_BUFFER && state != -1);
#else
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 void
gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
guint32 size;
guint8 *data, *end;
GstClockTime pts;
const mpeg2_info_t *info;
mpeg2_state_t state;
gboolean done = FALSE;
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
{
GstClockTime time;
if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &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));
}
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
gst_mpeg2dec_flush_decoder (mpeg2dec);
gst_pad_event_default (pad, event);
return;
}
case GST_EVENT_EOS:
if (mpeg2dec->index && mpeg2dec->closed) {
gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
}
default:
GST_DEBUG_OBJECT (mpeg2dec, "Got event of type %d on sink pad",
GST_EVENT_TYPE (event));
gst_pad_event_default (pad, event);
return;
}
}
size = GST_BUFFER_SIZE (buf);
data = GST_BUFFER_DATA (buf);
pts = GST_BUFFER_TIMESTAMP (buf);
GST_LOG_OBJECT (mpeg2dec, "received buffer, timestamp %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
info = mpeg2_info (mpeg2dec->decoder);
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");
while (!done) {
gboolean slice = FALSE;
GST_LOG_OBJECT (mpeg2dec, "calling parse");
state = mpeg2_parse (mpeg2dec->decoder);
GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state);
switch (state) {
case STATE_SEQUENCE:
static gboolean
handle_sequence (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
{
gint i;
@ -684,14 +607,12 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
mpeg2dec->frame_rate = fpss[i];
}
}
mpeg2dec->frame_period =
info->sequence->frame_period * GST_USECOND / 27;
mpeg2dec->frame_period = info->sequence->frame_period * GST_USECOND / 27;
GST_DEBUG_OBJECT (mpeg2dec,
"sequence flags: %d, frame period: %d (%g), frame rate: %g",
info->sequence->flags, info->sequence->frame_period,
(double) (mpeg2dec->frame_period) / GST_SECOND,
mpeg2dec->frame_rate);
(double) (mpeg2dec->frame_period) / GST_SECOND, mpeg2dec->frame_rate);
GST_DEBUG_OBJECT (mpeg2dec, "profile: %02x, colour_primaries: %d",
info->sequence->profile_level_id, info->sequence->colour_primaries);
GST_DEBUG_OBJECT (mpeg2dec, "transfer chars: %d, matrix coef: %d",
@ -700,33 +621,24 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
if (!gst_mpeg2dec_negotiate_format (mpeg2dec)) {
GST_ELEMENT_ERROR (mpeg2dec, CORE, NEGOTIATION, (NULL), (NULL));
goto exit;
return FALSE;
}
if (!mpeg2dec->have_fbuf) {
/* alloc 3 buffers */
gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
/* alloc 2 buffers */
if (!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset) ||
!gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset))
return FALSE;
mpeg2dec->have_fbuf = TRUE;
}
mpeg2dec->need_sequence = FALSE;
if (mpeg2dec->pending_event) {
done =
GST_EVENT_SEEK_FLAGS (mpeg2dec->
pending_event) & GST_SEEK_FLAG_FLUSH;
gst_mpeg2dec_src_event (mpeg2dec->srcpad, mpeg2dec->pending_event);
mpeg2dec->pending_event = NULL;
return TRUE;
}
break;
}
case STATE_SEQUENCE_REPEATED:
GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
case STATE_GOP:
break;
case STATE_PICTURE:
static gboolean
handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
{
gboolean key_frame = FALSE;
GstBuffer *outbuf;
@ -736,13 +648,14 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
(info->current_picture->flags & PIC_MASK_CODING_TYPE) ==
PIC_FLAG_CODING_TYPE_I;
}
outbuf =
gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
outbuf = gst_mpeg2dec_alloc_buffer (mpeg2dec, mpeg2dec->offset);
if (!outbuf)
return FALSE;
GST_DEBUG_OBJECT (mpeg2dec, "picture %s, outbuf %p, offset %"
G_GINT64_FORMAT ", pts %" G_GINT64_FORMAT,
key_frame ? ", kf," : " ", outbuf, GST_BUFFER_OFFSET (outbuf),
pts);
G_GINT64_FORMAT,
key_frame ? ", kf," : " ", outbuf, GST_BUFFER_OFFSET (outbuf)
);
if (mpeg2dec->discont_state == MPEG2DEC_DISC_NEW_PICTURE && key_frame)
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_KEYFRAME;
@ -751,28 +664,16 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
mpeg2_skip (mpeg2dec->decoder, 1);
else
mpeg2_skip (mpeg2dec->decoder, 0);
break;
return TRUE;
}
case STATE_SLICE_1ST:
GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered");
break;
case STATE_PICTURE_2ND:
GST_LOG_OBJECT (mpeg2dec,
"Second picture header encountered. Decoding 2nd field");
break;
case STATE_SLICE:
slice = TRUE;
#if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
case STATE_INVALID_END:
#endif
case STATE_END:
static gboolean
handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
{
GstBuffer *outbuf = NULL;
gboolean skip = FALSE;
if (!slice) {
mpeg2dec->need_sequence = TRUE;
}
GST_DEBUG_OBJECT (mpeg2dec, "picture slice/end %p %p %p %p",
info->display_fbuf,
info->display_picture, info->current_picture,
@ -782,7 +683,15 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
const mpeg2_picture_t *picture;
gboolean key_frame = FALSE;
outbuf = (GstBuffer *) 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;
key_frame =
@ -792,8 +701,7 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
if (key_frame) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_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;
#if MPEG2_RELEASE < MPEG2_VERSION(0,4,0)
@ -820,8 +728,7 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
/* 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;
info->display_picture_2nd->nb_fields) * mpeg2dec->frame_period / 2;
} else {
GST_BUFFER_DURATION (outbuf) =
picture->nb_fields * mpeg2dec->frame_period / 2;
@ -872,28 +779,267 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
(mpeg2dec->decoded_width > mpeg2dec->width))
outbuf = crop_buffer (mpeg2dec, outbuf);
if (info->current_picture
&& (info->current_picture->flags & PIC_MASK_CODING_TYPE) ==
PIC_FLAG_CODING_TYPE_I) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
} else {
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_KEY_UNIT);
}
gst_pad_push (mpeg2dec->srcpad, GST_DATA (outbuf));
}
} else if (info->display_fbuf && !info->display_fbuf->id) {
GST_WARNING ("Got a frame from libmpeg2, but it has no buffer");
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("libmpeg2 reported invalid buffer %p", info->discard_fbuf->id));
}
if (info->discard_fbuf && info->discard_fbuf->id) {
gst_buffer_unref ((GstBuffer *) 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);
} else {
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("libmpeg2 reported invalid buffer %p", info->discard_fbuf->id));
}
}
return TRUE;
}
#if 0
static void
update_streaminfo (GstMpeg2dec * mpeg2dec)
{
GstCaps *caps;
GstProps *props;
GstPropsEntry *entry;
const mpeg2_info_t *info;
info = mpeg2_info (mpeg2dec->decoder);
props = gst_props_empty_new ();
entry =
gst_props_entry_new ("framerate",
G_TYPE_DOUBLE (GST_SECOND / (float) mpeg2dec->frame_period));
gst_props_add_entry (props, entry);
entry =
gst_props_entry_new ("bitrate",
G_TYPE_INT (info->sequence->byte_rate * 8));
gst_props_add_entry (props, entry);
caps = gst_caps_new ("mpeg2dec_streaminfo",
"application/x-gst-streaminfo", props);
gst_caps_replace_sink (&mpeg2dec->streaminfo, caps);
g_object_notify (G_OBJECT (mpeg2dec), "streaminfo");
}
#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_PICTURE:
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 && 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);
} else {
GST_ELEMENT_ERROR (mpeg2dec, LIBRARY, TOO_LAZY, (NULL),
("libmpeg2 reported invalid buffer %p",
info->discard_fbuf->id));
}
}
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);
}
}
static void
gst_mpeg2dec_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad));
guint32 size;
guint8 *data, *end;
GstClockTime pts;
const mpeg2_info_t *info;
mpeg2_state_t state;
gboolean done = FALSE;
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
{
GstClockTime time;
if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &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));
}
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
gst_mpeg2dec_flush_decoder (mpeg2dec);
gst_pad_event_default (pad, event);
return;
}
case GST_EVENT_FLUSH:
{
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
gst_mpeg2dec_flush_decoder (mpeg2dec);
gst_pad_event_default (pad, event);
return;
}
case GST_EVENT_EOS:
if (mpeg2dec->index && mpeg2dec->closed) {
gst_index_commit (mpeg2dec->index, mpeg2dec->index_id);
}
default:
GST_DEBUG_OBJECT (mpeg2dec, "Got event of type %d on sink pad",
GST_EVENT_TYPE (event));
gst_pad_event_default (pad, event);
return;
}
}
size = GST_BUFFER_SIZE (buf);
data = GST_BUFFER_DATA (buf);
pts = GST_BUFFER_TIMESTAMP (buf);
GST_LOG_OBJECT (mpeg2dec, "received buffer, timestamp %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
info = mpeg2_info (mpeg2dec->decoder);
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);
while (!done) {
GST_LOG_OBJECT (mpeg2dec, "calling parse");
state = mpeg2_parse (mpeg2dec->decoder);
GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state);
switch (state) {
case STATE_SEQUENCE:
if (!handle_sequence (mpeg2dec, info)) {
gst_mpeg2dec_flush_decoder (mpeg2dec);
goto exit;
}
if (mpeg2dec->pending_event) {
done =
GST_EVENT_SEEK_FLAGS (mpeg2dec->
pending_event) & GST_SEEK_FLAG_FLUSH;
gst_mpeg2dec_src_event (mpeg2dec->srcpad, mpeg2dec->pending_event);
mpeg2dec->pending_event = NULL;
}
break;
case STATE_SEQUENCE_REPEATED:
GST_DEBUG_OBJECT (mpeg2dec, "sequence repeated");
case STATE_GOP:
break;
case STATE_PICTURE:
{
if (!handle_picture (mpeg2dec, info)) {
gst_mpeg2dec_flush_decoder (mpeg2dec);
goto exit;
}
break;
}
/* need more data */
case STATE_SLICE_1ST:
GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered");
break;
case STATE_PICTURE_2ND:
GST_LOG_OBJECT (mpeg2dec,
"Second picture header encountered. Decoding 2nd field");
break;
#if MPEG2_RELEASE >= MPEG2_VERSION (0, 4, 0)
case STATE_INVALID_END:
#endif
case STATE_END:
mpeg2dec->need_sequence = TRUE;
case STATE_SLICE:
if (!handle_slice (mpeg2dec, info)) {
gst_mpeg2dec_flush_decoder (mpeg2dec);
goto exit;
}
if (state != STATE_SLICE)
gst_mpeg2dec_flush_decoder (mpeg2dec);
break;
case STATE_BUFFER:
case -1:
/* need more data */
done = TRUE;
break;
/* error */
case STATE_INVALID:
GST_WARNING_OBJECT (mpeg2dec, "Decoding error");
/* it looks like setting a new frame in libmpeg2 avoids a crash */
/* FIXME figure out how this screws up sync and buffer leakage */
gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf));
/*
* We need to close the decoder here, according to docs
*/
gst_mpeg2dec_close_decoder (mpeg2dec);
gst_mpeg2dec_open_decoder (mpeg2dec);
goto exit;
break;
default:
GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state);

View file

@ -41,6 +41,8 @@ G_BEGIN_DECLS
#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_MPEG2DEC_NUM_BUFS 3
typedef struct _GstMpeg2dec GstMpeg2dec;
typedef struct _GstMpeg2decClass GstMpeg2decClass;
@ -71,6 +73,8 @@ struct _GstMpeg2dec {
gboolean closed;
gboolean have_fbuf;
GstBuffer *buffers[GST_MPEG2DEC_NUM_BUFS];
DiscontState discont_state;
/* the timestamp of the next frame */
@ -89,6 +93,8 @@ struct _GstMpeg2dec {
gint frame_rate_code;
gint64 total_frames;
gint64 frame_period;
guint64 offset;
gdouble frame_rate;
gboolean need_sequence;