ext/mpeg2dec/gstmpeg2dec.*: Add buffer clipping.
Original commit message from CVS: * ext/mpeg2dec/gstmpeg2dec.c: (clear_queued), (flush_queued), (handle_picture), (clip_buffer), (handle_slice), (gst_mpeg2dec_chain), (gst_mpeg2dec_sink_event), (gst_mpeg2dec_change_state): * ext/mpeg2dec/gstmpeg2dec.h: Add buffer clipping. Add basic reverse playback support. Not complete yet when dealing with non-closed GOPs.
This commit is contained in:
parent
0d018f956a
commit
30d994fafa
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
|||||||
|
2008-01-10 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||||
|
|
||||||
|
* ext/mpeg2dec/gstmpeg2dec.c: (clear_queued), (flush_queued),
|
||||||
|
(handle_picture), (clip_buffer), (handle_slice),
|
||||||
|
(gst_mpeg2dec_chain), (gst_mpeg2dec_sink_event),
|
||||||
|
(gst_mpeg2dec_change_state):
|
||||||
|
* ext/mpeg2dec/gstmpeg2dec.h:
|
||||||
|
Add buffer clipping.
|
||||||
|
Add basic reverse playback support. Not complete yet when dealing with
|
||||||
|
non-closed GOPs.
|
||||||
|
|
||||||
2008-01-10 Sebastian Dröge <slomo@circular-chaos.org>
|
2008-01-10 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
* autogen.sh:
|
* autogen.sh:
|
||||||
|
@ -680,6 +680,35 @@ clear_buffers (GstMpeg2dec * mpeg2dec)
|
|||||||
*bufpen = NULL;
|
*bufpen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_queued (GstMpeg2dec * mpeg2dec)
|
||||||
|
{
|
||||||
|
g_list_foreach (mpeg2dec->queued, (GFunc) gst_mini_object_unref, NULL);
|
||||||
|
g_list_free (mpeg2dec->queued);
|
||||||
|
mpeg2dec->queued = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
flush_queued (GstMpeg2dec * mpeg2dec)
|
||||||
|
{
|
||||||
|
GstFlowReturn res;
|
||||||
|
|
||||||
|
while (mpeg2dec->queued) {
|
||||||
|
GstBuffer *buf = GST_BUFFER_CAST (mpeg2dec->queued->data);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mpeg2dec, "pushing buffer %p, timestamp %"
|
||||||
|
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
|
||||||
|
|
||||||
|
/* iterate ouput queue an push downstream */
|
||||||
|
res = gst_pad_push (mpeg2dec->srcpad, buf);
|
||||||
|
|
||||||
|
mpeg2dec->queued = g_list_delete_link (mpeg2dec->queued, mpeg2dec->queued);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
{
|
{
|
||||||
@ -705,6 +734,11 @@ handle_picture (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case PIC_FLAG_CODING_TYPE_I:
|
case PIC_FLAG_CODING_TYPE_I:
|
||||||
mpeg2_skip (mpeg2dec->decoder, 0);
|
mpeg2_skip (mpeg2dec->decoder, 0);
|
||||||
|
if (mpeg2dec->segment.rate < 0.0) {
|
||||||
|
/* negative rate, flush the queued pictures in reverse */
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "flushing queued buffers");
|
||||||
|
flush_queued (mpeg2dec);
|
||||||
|
}
|
||||||
case PIC_FLAG_CODING_TYPE_P:
|
case PIC_FLAG_CODING_TYPE_P:
|
||||||
bufpen = &mpeg2dec->ip_buffers[mpeg2dec->ip_bufpos];
|
bufpen = &mpeg2dec->ip_buffers[mpeg2dec->ip_bufpos];
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "I/P unref %p, ref %p", *bufpen, outbuf);
|
GST_DEBUG_OBJECT (mpeg2dec, "I/P unref %p, ref %p", *bufpen, outbuf);
|
||||||
@ -741,6 +775,49 @@ no_buffer:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* try to clip the buffer to the segment boundaries */
|
||||||
|
static gboolean
|
||||||
|
clip_buffer (GstMpeg2dec * dec, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
gboolean res = TRUE;
|
||||||
|
GstClockTime in_ts, in_dur, stop;
|
||||||
|
gint64 cstart, cstop;
|
||||||
|
|
||||||
|
in_ts = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
in_dur = GST_BUFFER_DURATION (buf);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (dec,
|
||||||
|
"timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur));
|
||||||
|
|
||||||
|
/* can't clip without TIME segment */
|
||||||
|
if (dec->segment.format != GST_FORMAT_TIME)
|
||||||
|
goto beach;
|
||||||
|
|
||||||
|
/* we need a start time */
|
||||||
|
if (!GST_CLOCK_TIME_IS_VALID (in_ts))
|
||||||
|
goto beach;
|
||||||
|
|
||||||
|
/* generate valid stop, if duration unknown, we have unknown stop */
|
||||||
|
stop =
|
||||||
|
GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
/* now clip */
|
||||||
|
if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
|
||||||
|
in_ts, stop, &cstart, &cstop)))
|
||||||
|
goto beach;
|
||||||
|
|
||||||
|
/* update timestamp and possibly duration if the clipped stop time is
|
||||||
|
* valid */
|
||||||
|
GST_BUFFER_TIMESTAMP (buf) = cstart;
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (cstop))
|
||||||
|
GST_BUFFER_DURATION (buf) = cstop - cstart;
|
||||||
|
|
||||||
|
beach:
|
||||||
|
GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
||||||
{
|
{
|
||||||
@ -838,6 +915,10 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
|||||||
if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE)
|
if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
|
/* check for clipping */
|
||||||
|
if (!clip_buffer (mpeg2dec, outbuf))
|
||||||
|
goto clipped;
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (time)) {
|
if (GST_CLOCK_TIME_IS_VALID (time)) {
|
||||||
gboolean need_skip;
|
gboolean need_skip;
|
||||||
GstClockTime qostime;
|
GstClockTime qostime;
|
||||||
@ -859,12 +940,6 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
|||||||
goto dropping_qos;
|
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)));
|
|
||||||
|
|
||||||
/* ref before pushing it out, so we still have the ref in our
|
/* ref before pushing it out, so we still have the ref in our
|
||||||
* array of buffers */
|
* array of buffers */
|
||||||
gst_buffer_ref (outbuf);
|
gst_buffer_ref (outbuf);
|
||||||
@ -872,8 +947,24 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
|
|||||||
/* do cropping if needed */
|
/* do cropping if needed */
|
||||||
crop_buffer (mpeg2dec, &outbuf);
|
crop_buffer (mpeg2dec, &outbuf);
|
||||||
|
|
||||||
|
if (mpeg2dec->segment.rate >= 0.0) {
|
||||||
|
/* forward: push right away */
|
||||||
|
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)));
|
||||||
|
|
||||||
ret = gst_pad_push (mpeg2dec->srcpad, outbuf);
|
ret = gst_pad_push (mpeg2dec->srcpad, outbuf);
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "pushed with result %s", gst_flow_get_name (ret));
|
GST_DEBUG_OBJECT (mpeg2dec, "pushed with result %s",
|
||||||
|
gst_flow_get_name (ret));
|
||||||
|
} else {
|
||||||
|
/* reverse: queue, we'll push in reverse when we receive the next (previous)
|
||||||
|
* keyframe. */
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "queued frame");
|
||||||
|
mpeg2dec->queued = g_list_prepend (mpeg2dec->queued, outbuf);
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -894,6 +985,11 @@ drop:
|
|||||||
mpeg2dec->discont_state);
|
mpeg2dec->discont_state);
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
clipped:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, clipped");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
dropping_qos:
|
dropping_qos:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of QoS");
|
GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer because of QoS");
|
||||||
@ -949,6 +1045,15 @@ gst_mpeg2dec_chain (GstPad * pad, GstBuffer * buf)
|
|||||||
data = GST_BUFFER_DATA (buf);
|
data = GST_BUFFER_DATA (buf);
|
||||||
pts = GST_BUFFER_TIMESTAMP (buf);
|
pts = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
|
||||||
|
if (GST_BUFFER_IS_DISCONT (buf)) {
|
||||||
|
GST_LOG_OBJECT (mpeg2dec, "DISCONT, reset decoder");
|
||||||
|
/* when we receive a discont, reset our state as to not create too much
|
||||||
|
* distortion in the picture due to missing packets */
|
||||||
|
mpeg2_reset (mpeg2dec->decoder, 0);
|
||||||
|
mpeg2_skip (mpeg2dec->decoder, 1);
|
||||||
|
mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE;
|
||||||
|
}
|
||||||
|
|
||||||
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)),
|
||||||
@ -1095,13 +1200,15 @@ gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
|
|||||||
if (format != GST_FORMAT_TIME)
|
if (format != GST_FORMAT_TIME)
|
||||||
goto newseg_wrong_format;
|
goto newseg_wrong_format;
|
||||||
|
|
||||||
if (rate <= 0.0)
|
|
||||||
goto newseg_wrong_rate;
|
|
||||||
|
|
||||||
/* now configure the values */
|
/* now configure the values */
|
||||||
gst_segment_set_newsegment_full (&mpeg2dec->segment, update,
|
gst_segment_set_newsegment_full (&mpeg2dec->segment, update,
|
||||||
rate, arate, format, start, stop, time);
|
rate, arate, format, start, stop, time);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mpeg2dec,
|
||||||
|
"Pushing newseg rate %g, applied rate %g, format %d, start %"
|
||||||
|
G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", pos %" G_GINT64_FORMAT,
|
||||||
|
rate, arate, format, start, stop, time);
|
||||||
|
|
||||||
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1115,6 +1222,7 @@ gst_mpeg2dec_sink_event (GstPad * pad, GstEvent * event)
|
|||||||
gst_mpeg2dec_qos_reset (mpeg2dec);
|
gst_mpeg2dec_qos_reset (mpeg2dec);
|
||||||
mpeg2_reset (mpeg2dec->decoder, 0);
|
mpeg2_reset (mpeg2dec->decoder, 0);
|
||||||
mpeg2_skip (mpeg2dec->decoder, 1);
|
mpeg2_skip (mpeg2dec->decoder, 1);
|
||||||
|
clear_queued (mpeg2dec);
|
||||||
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
ret = gst_pad_push_event (mpeg2dec->srcpad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1141,12 +1249,6 @@ newseg_wrong_format:
|
|||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
newseg_wrong_rate:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (mpeg2dec, "negative rates not supported yet");
|
|
||||||
gst_event_unref (event);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -1615,6 +1717,7 @@ gst_mpeg2dec_change_state (GstElement * element, GstStateChange transition)
|
|||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
gst_mpeg2dec_qos_reset (mpeg2dec);
|
gst_mpeg2dec_qos_reset (mpeg2dec);
|
||||||
|
clear_queued (mpeg2dec);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
if (mpeg2dec->decoder) {
|
if (mpeg2dec->decoder) {
|
||||||
|
@ -116,6 +116,11 @@ struct _GstMpeg2dec {
|
|||||||
/* QoS stuff */ /* with LOCK*/
|
/* QoS stuff */ /* with LOCK*/
|
||||||
gdouble proportion;
|
gdouble proportion;
|
||||||
GstClockTime earliest_time;
|
GstClockTime earliest_time;
|
||||||
|
|
||||||
|
/* gather/decode queues for reverse playback */
|
||||||
|
GList *gather;
|
||||||
|
GList *decode;
|
||||||
|
GList *queued;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMpeg2decClass {
|
struct _GstMpeg2decClass {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user