ext/faad/gstfaad.c: Add query function for position/duration querying (mostly for raw AAC streams); make seeking in r...

Original commit message from CVS:
* ext/faad/gstfaad.c: (gst_faad_init), (gst_faad_send_tags),
(gst_faad_setcaps), (gst_faad_do_raw_seek), (gst_faad_src_event),
(gst_faad_sink_event), (gst_faad_src_convert),
(gst_faad_src_query), (gst_faad_chain), (gst_faad_change_state):
Add query function for position/duration querying (mostly for
raw AAC streams); make seeking in raw AAC streams work; post
tags with codec name if this is a raw AAC stream.
This commit is contained in:
Tim-Philipp Müller 2006-03-04 20:04:11 +00:00
parent 3152fa1872
commit cc497a721a
2 changed files with 256 additions and 22 deletions

View file

@ -1,3 +1,13 @@
2006-03-04 Tim-Philipp Müller <tim at centricular dot net>
* ext/faad/gstfaad.c: (gst_faad_init), (gst_faad_send_tags),
(gst_faad_setcaps), (gst_faad_do_raw_seek), (gst_faad_src_event),
(gst_faad_sink_event), (gst_faad_src_convert),
(gst_faad_src_query), (gst_faad_chain), (gst_faad_change_state):
Add query function for position/duration querying (mostly for
raw AAC streams); make seeking in raw AAC streams work; post
tags with codec name if this is a raw AAC stream.
2006-03-04 Sebastien Moutte <sebastien@moutte.net>
* sys/directdraw:

View file

@ -114,10 +114,14 @@ static void gst_faad_init (GstFaad * faad);
static gboolean gst_faad_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_faad_srcgetcaps (GstPad * pad);
static gboolean gst_faad_event (GstPad * pad, GstEvent * event);
static gboolean gst_faad_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_faad_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_faad_src_query (GstPad * pad, GstQuery * query);
static GstFlowReturn gst_faad_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn gst_faad_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_faad_src_convert (GstFaad * faad, GstFormat src_format,
gint64 src_val, GstFormat dest_format, gint64 * dest_val);
static GstElementClass *parent_class; /* NULL */
@ -192,7 +196,7 @@ gst_faad_init (GstFaad * faad)
"sink");
gst_element_add_pad (GST_ELEMENT (faad), faad->sinkpad);
gst_pad_set_event_function (faad->sinkpad,
GST_DEBUG_FUNCPTR (gst_faad_event));
GST_DEBUG_FUNCPTR (gst_faad_sink_event));
gst_pad_set_setcaps_function (faad->sinkpad,
GST_DEBUG_FUNCPTR (gst_faad_setcaps));
gst_pad_set_chain_function (faad->sinkpad,
@ -201,10 +205,27 @@ gst_faad_init (GstFaad * faad)
faad->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
"src");
gst_element_add_pad (GST_ELEMENT (faad), faad->srcpad);
gst_pad_use_fixed_caps (faad->srcpad);
gst_pad_set_getcaps_function (faad->srcpad,
GST_DEBUG_FUNCPTR (gst_faad_srcgetcaps));
gst_pad_set_query_function (faad->srcpad,
GST_DEBUG_FUNCPTR (gst_faad_src_query));
gst_pad_set_event_function (faad->srcpad,
GST_DEBUG_FUNCPTR (gst_faad_src_event));
gst_element_add_pad (GST_ELEMENT (faad), faad->srcpad);
}
static void
gst_faad_send_tags (GstFaad * faad)
{
GstTagList *tags;
tags = gst_tag_list_new ();
gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
GST_TAG_AUDIO_CODEC, "MPEG-4 AAC audio", NULL);
gst_element_found_tags (GST_ELEMENT (faad), tags);
}
static gboolean
@ -257,6 +278,9 @@ gst_faad_setcaps (GstPad * pad, GstCaps * caps)
faad->need_channel_setup = TRUE;
if (!faad->packetised)
gst_faad_send_tags (faad);
return TRUE;
}
@ -657,18 +681,77 @@ gst_faad_srcconnect (GstPad * pad, const GstCaps * caps)
}*/
static gboolean
gst_faad_event (GstPad * pad, GstEvent * event)
gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
{
GstSeekFlags flags;
GstSeekType start_type, end_type;
GstFormat format;
gdouble rate;
gint64 start, start_time;
gst_event_parse_seek (event, &rate, &format, &flags, &start_type,
&start_time, &end_type, NULL);
if (rate != 1.0 ||
format != GST_FORMAT_TIME ||
start_type != GST_SEEK_TYPE_SET || end_type != GST_SEEK_TYPE_NONE) {
return FALSE;
}
if (!gst_faad_src_convert (faad, GST_FORMAT_TIME, start_time,
GST_FORMAT_BYTES, &start)) {
return FALSE;
}
event = gst_event_new_seek (1.0, GST_FORMAT_BYTES, flags,
GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_NONE, -1);
GST_DEBUG_OBJECT (faad, "seeking to %" GST_TIME_FORMAT " at byte offset %"
G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start);
return gst_pad_send_event (GST_PAD_PEER (faad->sinkpad), event);
}
static gboolean
gst_faad_src_event (GstPad * pad, GstEvent * event)
{
GstFaad *faad;
gboolean res;
faad = GST_FAAD (gst_pad_get_parent (pad));
GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:{
/* try upstream first, there might be a demuxer */
gst_event_ref (event);
if (!(res = gst_pad_event_default (pad, event))) {
res = gst_faad_do_raw_seek (faad, event);
}
gst_event_unref (event);
break;
}
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (faad);
return res;
}
static gboolean
gst_faad_sink_event (GstPad * pad, GstEvent * event)
{
GstFaad *faad;
gboolean res = TRUE;
faad = GST_FAAD (gst_pad_get_parent (pad));
GST_LOG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event));
/* FIXME: we should probably handle FLUSH and also
* SEEK in the case where we are not in a container
* (when our newsegment was in BYTES) */
/* FIXME: we should probably handle FLUSH */
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
if (faad->tempbuf != NULL) {
@ -691,31 +774,33 @@ gst_faad_event (GstPad * pad, GstEvent * event)
GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
GST_TIME_ARGS (end));
} else if (fmt == GST_FORMAT_BYTES) {
GstEvent *new_ev;
guint64 new_start = 0;
guint64 new_end = GST_CLOCK_TIME_NONE;
gint64 new_start = 0;
gint64 new_end = -1;
GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_BYTES (%"
G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT ")", start, end);
if (faad->bytes_in > 0 && faad->sum_dur_out > 0) {
/* try to convert based on the average bitrate so far */
new_start = (faad->sum_dur_out * start) / faad->bytes_in;
if (new_end != (guint64) - 1) {
new_end = (faad->sum_dur_out * end) / faad->bytes_in;
if (gst_faad_src_convert (faad, GST_FORMAT_BYTES, start,
GST_FORMAT_TIME, &new_start)) {
if (end != -1) {
gst_faad_src_convert (faad, GST_FORMAT_BYTES, end,
GST_FORMAT_TIME, &new_end);
}
} else {
GST_DEBUG
("no average bitrate yet, sending newsegment with start at 0");
}
new_ev =
gst_event_new_new_segment (is_update, rate, GST_FORMAT_TIME,
new_start, new_end, base);
gst_event_unref (event);
event = new_ev;
event = gst_event_new_new_segment (is_update, rate,
GST_FORMAT_TIME, new_start, new_end, new_start);
GST_DEBUG ("Sending new NEWSEGMENT event, time %" GST_TIME_FORMAT
" - %" GST_TIME_FORMAT, GST_TIME_ARGS (new_start),
GST_TIME_ARGS (new_end));
faad->next_ts = new_start;
faad->prev_ts = GST_CLOCK_TIME_NONE;
}
res = gst_pad_push_event (faad->srcpad, event);
@ -726,9 +811,141 @@ gst_faad_event (GstPad * pad, GstEvent * event)
break;
}
gst_object_unref (faad);
return res;
}
static gboolean
gst_faad_src_convert (GstFaad * faad, GstFormat src_format, gint64 src_val,
GstFormat dest_format, gint64 * dest_val)
{
guint64 bytes_in, time_out, val;
if (src_format == dest_format) {
if (dest_val)
*dest_val = src_val;
return TRUE;
}
GST_OBJECT_LOCK (faad);
bytes_in = faad->bytes_in;
time_out = faad->sum_dur_out;
GST_OBJECT_UNLOCK (faad);
if (bytes_in == 0 || time_out == 0)
return FALSE;
/* convert based on the average bitrate so far */
if (src_format == GST_FORMAT_BYTES && dest_format == GST_FORMAT_TIME) {
val = gst_util_uint64_scale (src_val, time_out, bytes_in);
} else if (src_format == GST_FORMAT_TIME && dest_format == GST_FORMAT_BYTES) {
val = gst_util_uint64_scale (src_val, bytes_in, time_out);
} else {
return FALSE;
}
if (dest_val)
*dest_val = (gint64) val;
return TRUE;
}
static gboolean
gst_faad_src_query (GstPad * pad, GstQuery * query)
{
gboolean res = FALSE;
GstFaad *faad;
GstPad *peer = NULL;
faad = GST_FAAD (gst_pad_get_parent (pad));
GST_LOG_OBJECT (faad, "processing %s query", GST_QUERY_TYPE_NAME (query));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:{
GstFormat format;
gint64 len_bytes, duration;
/* try upstream first, in case there's a demuxer */
if ((res = gst_pad_query_default (pad, query)))
break;
gst_query_parse_duration (query, &format, NULL);
if (format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (faad, "query failed: can't handle format %s",
gst_format_get_name (format));
break;
}
peer = gst_pad_get_peer (faad->sinkpad);
if (peer == NULL)
break;
format = GST_FORMAT_BYTES;
if (!gst_pad_query_duration (peer, &format, &len_bytes)) {
GST_DEBUG_OBJECT (faad, "query failed: failed to get upstream length");
break;
}
res = gst_faad_src_convert (faad, GST_FORMAT_BYTES, len_bytes,
GST_FORMAT_TIME, &duration);
if (res) {
gst_query_set_duration (query, GST_FORMAT_TIME, duration);
GST_LOG_OBJECT (faad, "duration estimate: %" GST_TIME_FORMAT,
GST_TIME_ARGS (duration));
}
break;
}
case GST_QUERY_POSITION:{
GstFormat format;
gint64 pos_bytes, pos;
/* try upstream first, in case there's a demuxer */
if ((res = gst_pad_query_default (pad, query)))
break;
gst_query_parse_position (query, &format, NULL);
if (format != GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (faad, "query failed: can't handle format %s",
gst_format_get_name (format));
break;
}
peer = gst_pad_get_peer (faad->sinkpad);
if (peer == NULL)
break;
format = GST_FORMAT_BYTES;
if (!gst_pad_query_position (peer, &format, &pos_bytes)) {
GST_OBJECT_LOCK (faad);
pos = faad->next_ts;
GST_OBJECT_UNLOCK (faad);
res = TRUE;
} else {
res = gst_faad_src_convert (faad, GST_FORMAT_BYTES, pos_bytes,
GST_FORMAT_TIME, &pos);
}
if (res) {
gst_query_set_position (query, GST_FORMAT_TIME, pos);
}
break;
}
default:
res = gst_pad_query_default (pad, query);
break;
}
if (peer)
gst_object_unref (peer);
gst_object_unref (faad);
return res;
}
static gboolean
gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info,
GstCaps ** p_caps)
@ -852,6 +1069,10 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
faad = GST_FAAD (gst_pad_get_parent (pad));
GST_OBJECT_LOCK (faad);
faad->bytes_in += GST_BUFFER_SIZE (buffer);
GST_OBJECT_UNLOCK (faad);
if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) {
/* some demuxers send multiple buffers in a row
* with the same timestamp (e.g. matroskademux) */
@ -901,6 +1122,7 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
/* make sure we create new caps below */
faad->samplerate = 0;
faad->channels = 0;
gst_faad_send_tags (faad);
}
/* decode cycle */
@ -981,8 +1203,10 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
GST_BUFFER_DURATION (outbuf) =
GST_FRAMES_TO_CLOCK_TIME (num_samples, faad->samplerate);
GST_OBJECT_LOCK (faad);
faad->next_ts += GST_BUFFER_DURATION (outbuf);
faad->sum_dur_out += GST_BUFFER_DURATION (outbuf);
GST_OBJECT_UNLOCK (faad);
GST_DEBUG ("pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%"
GST_TIME_FORMAT, GST_BUFFER_OFFSET (outbuf),
@ -1007,8 +1231,6 @@ next:
}
}
faad->bytes_in += input_size;
out:
if (caps)
@ -1060,6 +1282,8 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
faad->channel_positions = NULL;
faad->next_ts = 0;
faad->prev_ts = GST_CLOCK_TIME_NONE;
faad->bytes_in = 0;
faad->sum_dur_out = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
faacDecClose (faad->handle);