Implement seeking/query/convert on dvdec

Original commit message from CVS:
Implement seeking/query/convert on dvdec
This commit is contained in:
Wim Taymans 2002-06-16 14:45:46 +00:00
parent 9101d97ff2
commit db81699feb
2 changed files with 229 additions and 50 deletions

View file

@ -151,21 +151,27 @@ static GstTypeDefinition dv_definition = {
}; };
/* A number of functon prototypes are given so we can refer to them later. */ /* A number of functon prototypes are given so we can refer to them later. */
static void gst_dvdec_class_init (GstDVDecClass *klass); static void gst_dvdec_class_init (GstDVDecClass *klass);
static void gst_dvdec_init (GstDVDec *dvdec); static void gst_dvdec_init (GstDVDec *dvdec);
static gboolean gst_dvdec_src_query (GstPad *pad, GstPadQueryType type, static gboolean gst_dvdec_src_query (GstPad *pad, GstPadQueryType type,
GstFormat *format, gint64 *value); GstFormat *format, gint64 *value);
static gboolean gst_dvdec_sink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value);
static gboolean gst_dvdec_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value);
static void gst_dvdec_loop (GstElement *element); static gboolean gst_dvdec_handle_src_event (GstPad *pad, GstEvent *event);
static void gst_dvdec_loop (GstElement *element);
static GstElementStateReturn static GstElementStateReturn
gst_dvdec_change_state (GstElement *element); gst_dvdec_change_state (GstElement *element);
static void gst_dvdec_set_property (GObject *object, guint prop_id, static void gst_dvdec_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec); const GValue *value, GParamSpec *pspec);
static void gst_dvdec_get_property (GObject *object, guint prop_id, static void gst_dvdec_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec); GValue *value, GParamSpec *pspec);
/* The parent class pointer needs to be kept around for some object /* The parent class pointer needs to be kept around for some object
* operations. * operations.
@ -246,14 +252,19 @@ gst_dvdec_init(GstDVDec *dvdec)
dvdec->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_temp), "sink"); dvdec->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_temp), "sink");
gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad); gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad);
gst_pad_set_query_function (dvdec->sinkpad, NULL); gst_pad_set_query_function (dvdec->sinkpad, NULL);
gst_pad_set_convert_function (dvdec->sinkpad, gst_dvdec_sink_convert);
dvdec->videosrcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (video_src_temp), "video"); dvdec->videosrcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (video_src_temp), "video");
gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->videosrcpad); gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->videosrcpad);
gst_pad_set_query_function (dvdec->videosrcpad, gst_dvdec_src_query); gst_pad_set_query_function (dvdec->videosrcpad, gst_dvdec_src_query);
gst_pad_set_event_function (dvdec->videosrcpad, gst_dvdec_handle_src_event);
gst_pad_set_convert_function (dvdec->videosrcpad, gst_dvdec_src_convert);
dvdec->audiosrcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET(audio_src_temp), "audio"); dvdec->audiosrcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET(audio_src_temp), "audio");
gst_element_add_pad(GST_ELEMENT(dvdec),dvdec->audiosrcpad); gst_element_add_pad(GST_ELEMENT(dvdec),dvdec->audiosrcpad);
gst_pad_set_query_function (dvdec->audiosrcpad, gst_dvdec_src_query); gst_pad_set_query_function (dvdec->audiosrcpad, gst_dvdec_src_query);
gst_pad_set_event_function (dvdec->audiosrcpad, gst_dvdec_handle_src_event);
gst_pad_set_convert_function (dvdec->audiosrcpad, gst_dvdec_src_convert);
gst_element_set_loop_function (GST_ELEMENT (dvdec), gst_dvdec_loop); gst_element_set_loop_function (GST_ELEMENT (dvdec), gst_dvdec_loop);
@ -262,12 +273,111 @@ gst_dvdec_init(GstDVDec *dvdec)
dvdec->pool = NULL; dvdec->pool = NULL;
dvdec->length = 0; dvdec->length = 0;
dvdec->next_ts = 0LL; dvdec->next_ts = 0LL;
dvdec->need_discont = FALSE;
dvdec->framerate = 0;
dvdec->height = 0;
for (i = 0; i <4; i++) { for (i = 0; i <4; i++) {
dvdec->audio_buffers[i] = (gint16 *)g_malloc (DV_AUDIO_MAX_SAMPLES * sizeof (gint16)); dvdec->audio_buffers[i] = (gint16 *)g_malloc (DV_AUDIO_MAX_SAMPLES * sizeof (gint16));
} }
} }
static gboolean
gst_dvdec_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value)
{
gboolean res = TRUE;
GstDVDec *dvdec;
gint scale = 1;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
if (dvdec->length == 0)
return FALSE;
switch (src_format) {
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
*dest_format = GST_FORMAT_TIME;
case GST_FORMAT_TIME:
default:
res = FALSE;
}
break;
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
*dest_format = GST_FORMAT_BYTES;
case GST_FORMAT_BYTES:
if (pad == dvdec->videosrcpad)
scale = 720 * dvdec->height * dvdec->bpp;
else if (pad == dvdec->audiosrcpad)
scale = dvdec->decoder->audio->num_channels * 2;
/* fallthrough */
case GST_FORMAT_UNITS:
if (pad == dvdec->videosrcpad)
*dest_value = src_value * dvdec->framerate * scale / GST_SECOND;
else if (pad == dvdec->audiosrcpad)
*dest_value = src_value * dvdec->decoder->audio->frequency * scale / GST_SECOND;
break;
default:
res = FALSE;
}
break;
default:
res = FALSE;
}
return res;
}
static gboolean
gst_dvdec_sink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value)
{
gboolean res = TRUE;
GstDVDec *dvdec;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
if (dvdec->length == 0)
return FALSE;
switch (src_format) {
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
*dest_format = GST_FORMAT_TIME;
case GST_FORMAT_TIME:
*dest_value = src_value * GST_SECOND / (dvdec->length * dvdec->framerate);
break;
default:
res = FALSE;
}
break;
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
*dest_format = GST_FORMAT_BYTES;
case GST_FORMAT_BYTES:
{
guint64 frame;
/* calculate the frame */
frame = src_value * dvdec->framerate / GST_SECOND;
/* calculate the offset */
*dest_value = frame * dvdec->length;
break;
}
default:
res = FALSE;
}
break;
default:
res = FALSE;
}
return res;
}
static gboolean static gboolean
gst_dvdec_src_query (GstPad *pad, GstPadQueryType type, gst_dvdec_src_query (GstPad *pad, GstPadQueryType type,
GstFormat *format, gint64 *value) GstFormat *format, gint64 *value)
@ -282,21 +392,21 @@ gst_dvdec_src_query (GstPad *pad, GstPadQueryType type,
switch (*format) { switch (*format) {
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*format = GST_FORMAT_TIME; *format = GST_FORMAT_TIME;
case GST_FORMAT_TIME: default:
{ {
guint64 len; guint64 len;
GstFormat tmp_format;
len = gst_bytestream_length (dvdec->bs); len = gst_bytestream_length (dvdec->bs);
if (len != -1 && dvdec->length) { tmp_format = GST_FORMAT_TIME;
*value = (len * GST_SECOND) / (dvdec->length * 25); if (len == -1 || !gst_pad_convert (dvdec->sinkpad, GST_FORMAT_BYTES, len, &tmp_format, value)) {
}
else
return FALSE; return FALSE;
}
if (!gst_pad_convert (pad, GST_FORMAT_TIME, *value, format, value)) {
return FALSE;
}
break; break;
} }
default:
res = FALSE;
break;
} }
break; break;
case GST_PAD_QUERY_POSITION: case GST_PAD_QUERY_POSITION:
@ -304,7 +414,7 @@ gst_dvdec_src_query (GstPad *pad, GstPadQueryType type,
case GST_FORMAT_DEFAULT: case GST_FORMAT_DEFAULT:
*format = GST_FORMAT_TIME; *format = GST_FORMAT_TIME;
default: default:
*value = dvdec->next_ts; res = gst_pad_convert (pad, GST_FORMAT_TIME, dvdec->next_ts, format, value);
break; break;
} }
break; break;
@ -316,7 +426,7 @@ gst_dvdec_src_query (GstPad *pad, GstPadQueryType type,
} }
static gboolean static gboolean
gst_dvdec_handle_event (GstDVDec *dvdec) gst_dvdec_handle_sink_event (GstDVDec *dvdec)
{ {
guint32 remaining; guint32 remaining;
GstEvent *event; GstEvent *event;
@ -330,26 +440,73 @@ gst_dvdec_handle_event (GstDVDec *dvdec)
case GST_EVENT_EOS: case GST_EVENT_EOS:
gst_pad_event_default (dvdec->sinkpad, event); gst_pad_event_default (dvdec->sinkpad, event);
break; break;
case GST_EVENT_SEEK:
g_warning ("seek event\n");
gst_event_free (event);
break;
case GST_EVENT_FLUSH: case GST_EVENT_FLUSH:
g_warning ("flush event\n");
gst_event_free (event);
break; break;
case GST_EVENT_DISCONTINUOUS: case GST_EVENT_DISCONTINUOUS:
g_warning ("discont event\n"); {
gst_event_free (event); gint i;
gboolean found = FALSE;
GstFormat format;
format = GST_FORMAT_TIME;
/* try to get a timestamp from the discont formats */
for (i = 0; i < GST_EVENT_DISCONT_OFFSET_LEN(event); i++) {
if (gst_pad_convert (dvdec->sinkpad, GST_EVENT_DISCONT_OFFSET(event,i).format, GST_EVENT_DISCONT_OFFSET(event,i).value,
&format, &dvdec->next_ts))
{
found = TRUE;
break;
}
}
/* assume 0 then */
if (!found) {
dvdec->next_ts = 0LL;
}
dvdec->need_discont = TRUE;
break; break;
}
default: default:
g_warning ("unhandled event %d\n", type); g_warning ("unhandled event %d\n", type);
gst_event_free (event);
break; break;
} }
gst_event_free (event);
return TRUE; return TRUE;
} }
static gboolean
gst_dvdec_handle_src_event (GstPad *pad, GstEvent *event)
{
gboolean res = TRUE;
GstDVDec *dvdec;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
{
gint64 position;
GstFormat format;
/* first try to figure out the byteoffset of this seek event */
format = GST_FORMAT_BYTES;
if (!gst_pad_convert (dvdec->sinkpad, GST_EVENT_SEEK_FORMAT (event), GST_EVENT_SEEK_OFFSET (event),
&format, &position)) {
/* could not convert seek format to byte offset */
res = FALSE;
break;
}
/* seek to offset */
if (!gst_bytestream_seek (dvdec->bs, position, GST_SEEK_METHOD_SET)) {
res = FALSE;
}
break;
}
default:
res = FALSE;
break;
}
return res;
}
static void static void
gst_dvdec_loop (GstElement *element) gst_dvdec_loop (GstElement *element)
@ -357,7 +514,6 @@ gst_dvdec_loop (GstElement *element)
GstDVDec *dvdec; GstDVDec *dvdec;
GstBuffer *buf, *outbuf; GstBuffer *buf, *outbuf;
guint8 *inframe; guint8 *inframe;
gboolean PAL;
gint height; gint height;
guint32 length, got_bytes; guint32 length, got_bytes;
GstFormat format; GstFormat format;
@ -368,15 +524,16 @@ gst_dvdec_loop (GstElement *element)
/* first read enough bytes to parse the header */ /* first read enough bytes to parse the header */
got_bytes = gst_bytestream_peek_bytes (dvdec->bs, &inframe, header_size); got_bytes = gst_bytestream_peek_bytes (dvdec->bs, &inframe, header_size);
if (got_bytes < header_size) { if (got_bytes < header_size) {
gst_dvdec_handle_event (dvdec); gst_dvdec_handle_sink_event (dvdec);
return; return;
} }
dv_parse_header (dvdec->decoder, inframe); dv_parse_header (dvdec->decoder, inframe);
/* after parsing the header we know the size of the data */ /* after parsing the header we know the size of the data */
PAL = dv_system_50_fields (dvdec->decoder); dvdec->PAL = dv_system_50_fields (dvdec->decoder);
height = (PAL ? PAL_HEIGHT : NTSC_HEIGHT); dvdec->framerate = (dvdec->PAL ? 25 : 30);
length = (PAL ? PAL_BUFFER : NTSC_BUFFER); dvdec->height = height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT);
length = (dvdec->PAL ? PAL_BUFFER : NTSC_BUFFER);
if (length != dvdec->length) { if (length != dvdec->length) {
dvdec->length = length; dvdec->length = length;
@ -386,7 +543,7 @@ gst_dvdec_loop (GstElement *element)
/* then read the read data */ /* then read the read data */
got_bytes = gst_bytestream_read (dvdec->bs, &buf, length); got_bytes = gst_bytestream_read (dvdec->bs, &buf, length);
if (got_bytes < length) { if (got_bytes < length) {
gst_dvdec_handle_event (dvdec); gst_dvdec_handle_sink_event (dvdec);
return; return;
} }
@ -438,9 +595,18 @@ gst_dvdec_loop (GstElement *element)
} }
} }
/* if we did not negotiate yet, do it now */ format = GST_FORMAT_TIME;
if (!GST_PAD_CAPS (dvdec->audiosrcpad)) { gst_pad_query (dvdec->videosrcpad, GST_PAD_QUERY_POSITION, &format, &ts);
gst_pad_try_set_caps (dvdec->audiosrcpad,
if (GST_PAD_IS_CONNECTED (dvdec->audiosrcpad)) {
gint16 *a_ptr;
gint i, j;
dv_decode_full_audio (dvdec->decoder, GST_BUFFER_DATA (buf), dvdec->audio_buffers);
/* if we did not negotiate yet, do it now */
if (!GST_PAD_CAPS (dvdec->audiosrcpad)) {
gst_pad_try_set_caps (dvdec->audiosrcpad,
GST_CAPS_NEW ( GST_CAPS_NEW (
"dvdec_audio_caps", "dvdec_audio_caps",
"audio/raw", "audio/raw",
@ -453,16 +619,7 @@ gst_dvdec_loop (GstElement *element)
"channels", GST_PROPS_INT (dvdec->decoder->audio->num_channels), "channels", GST_PROPS_INT (dvdec->decoder->audio->num_channels),
"endianness", GST_PROPS_INT (G_LITTLE_ENDIAN) "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN)
)); ));
} }
format = GST_FORMAT_TIME;
gst_pad_query (dvdec->videosrcpad, GST_PAD_QUERY_POSITION, &format, &ts);
if (GST_PAD_IS_CONNECTED (dvdec->audiosrcpad)) {
gint16 *a_ptr;
gint i, j;
dv_decode_full_audio (dvdec->decoder, GST_BUFFER_DATA (buf), dvdec->audio_buffers);
outbuf = gst_buffer_new (); outbuf = gst_buffer_new ();
GST_BUFFER_SIZE (outbuf) = dvdec->decoder->audio->samples_this_frame * sizeof (gint16) * dvdec->decoder->audio->num_channels; GST_BUFFER_SIZE (outbuf) = dvdec->decoder->audio->samples_this_frame * sizeof (gint16) * dvdec->decoder->audio->num_channels;
@ -477,6 +634,13 @@ gst_dvdec_loop (GstElement *element)
} }
GST_BUFFER_TIMESTAMP (outbuf) = ts; GST_BUFFER_TIMESTAMP (outbuf) = ts;
if (dvdec->need_discont) {
GstEvent *discont;
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, ts, NULL);
gst_pad_push (dvdec->audiosrcpad, GST_BUFFER (discont));
}
gst_pad_push (dvdec->audiosrcpad, outbuf); gst_pad_push (dvdec->audiosrcpad, outbuf);
} }
@ -518,11 +682,22 @@ gst_dvdec_loop (GstElement *element)
GST_BUFFER_TIMESTAMP (outbuf) = ts; GST_BUFFER_TIMESTAMP (outbuf) = ts;
if (dvdec->need_discont) {
GstEvent *discont;
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, ts, NULL);
gst_pad_push (dvdec->videosrcpad, GST_BUFFER (discont));
}
gst_pad_push (dvdec->videosrcpad, outbuf); gst_pad_push (dvdec->videosrcpad, outbuf);
} }
/* FIXME this is inaccurate for NTSC */ /* FIXME this is inaccurate for NTSC */
dvdec->next_ts += GST_SECOND / (PAL ? 25 : 30); dvdec->next_ts += GST_SECOND / dvdec->framerate;
if (dvdec->need_discont) {
dvdec->need_discont = FALSE;
}
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }

View file

@ -53,8 +53,12 @@ struct _GstDVDec {
GstBufferPool *pool; GstBufferPool *pool;
dv_color_space_t space; dv_color_space_t space;
gint bpp; gint bpp;
gboolean PAL;
gint framerate;
gint height;
gint length; gint length;
guint64 next_ts; guint64 next_ts;
gboolean need_discont;
gint16 *audio_buffers[4]; gint16 *audio_buffers[4];
}; };