summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>2005-02-05 16:28:32 +0000
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>2005-02-05 16:28:32 +0000
commit578c888cc0338a3109fc0e44635a83c0a63e6eb4 (patch)
treee621f7394c20ce560123968067d566e691cd555e
parentc02af2b60828ad97929c1b485e076fc6a1395901 (diff)
downloadgstreamer-plugins-good-578c888cc0338a3109fc0e44635a83c0a63e6eb4.tar.gz
examples/seeking/seek.c: Add AVI pipeline.
Original commit message from CVS: * examples/seeking/seek.c: (make_avi_msmpeg4v3_mp3_pipeline): Add AVI pipeline. * gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps), (gst_riff_create_audio_caps), (gst_riff_create_iavs_caps), (gst_riff_create_video_template_caps), (gst_riff_create_audio_template_caps), (gst_riff_create_iavs_template_caps): * gst-libs/gst/riff/riff-media.h: Remove obsolete non-data functions, make data functions the default. * gst-libs/gst/riff/riff-read.c: (gst_riff_read_chunk), (gst_riff_parse_chunk), (gst_riff_parse_file_header), (gst_riff_parse_strh), (gst_riff_parse_strf_vids), (gst_riff_parse_strf_auds), (gst_riff_parse_strf_iavs), (gst_riff_parse_info): * gst-libs/gst/riff/riff-read.h: * gst-libs/gst/riff/riff.c: (plugin_init): Change from bytestream-wrapping to pure RIFF parsing (can be used chain-based if someone would want that). Add gtk-doc comments. * gst/avi/Makefile.am: * gst/avi/gstavi.c: (plugin_init): Disable mux for now. * gst/avi/gstavidemux.c: (gst_avi_demux_get_type), (gst_avi_demux_class_init), (gst_avi_demux_init), (gst_avi_demux_reset), (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event), (gst_avi_demux_parse_file_header), (gst_avi_demux_stream_init), (gst_avi_demux_parse_avih), (gst_avi_demux_parse_superindex), (gst_avi_demux_parse_subindex), (gst_avi_demux_read_subindexes), (gst_avi_demux_parse_stream), (gst_avi_demux_parse_odml), (gst_avi_demux_parse_index), (gst_avi_demux_stream_index), (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index), (gst_avi_demux_stream_header), (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data), (gst_avi_demux_loop), (gst_avi_demux_sink_activate): * gst/avi/gstavidemux.h: Port to changed RIFF API, port to 0.9, add locking. Add gtk-doc comments to some relevant functions. Seeking is weird, works otherwise. Some parts are still disabled.
-rw-r--r--ChangeLog42
-rw-r--r--examples/seeking/seek.c68
-rw-r--r--gst/avi/Makefile.am6
-rw-r--r--gst/avi/gstavi.c7
-rw-r--r--gst/avi/gstavidemux.c1522
-rw-r--r--gst/avi/gstavidemux.h25
6 files changed, 911 insertions, 759 deletions
diff --git a/ChangeLog b/ChangeLog
index 3de8b2409..888c46e65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2005-02-05 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+ * examples/seeking/seek.c: (make_avi_msmpeg4v3_mp3_pipeline):
+ Add AVI pipeline.
+ * gst-libs/gst/riff/riff-media.c: (gst_riff_create_video_caps),
+ (gst_riff_create_audio_caps), (gst_riff_create_iavs_caps),
+ (gst_riff_create_video_template_caps),
+ (gst_riff_create_audio_template_caps),
+ (gst_riff_create_iavs_template_caps):
+ * gst-libs/gst/riff/riff-media.h:
+ Remove obsolete non-data functions, make data functions the
+ default.
+ * gst-libs/gst/riff/riff-read.c: (gst_riff_read_chunk),
+ (gst_riff_parse_chunk), (gst_riff_parse_file_header),
+ (gst_riff_parse_strh), (gst_riff_parse_strf_vids),
+ (gst_riff_parse_strf_auds), (gst_riff_parse_strf_iavs),
+ (gst_riff_parse_info):
+ * gst-libs/gst/riff/riff-read.h:
+ * gst-libs/gst/riff/riff.c: (plugin_init):
+ Change from bytestream-wrapping to pure RIFF parsing (can be used
+ chain-based if someone would want that). Add gtk-doc comments.
+ * gst/avi/Makefile.am:
+ * gst/avi/gstavi.c: (plugin_init):
+ Disable mux for now.
+ * gst/avi/gstavidemux.c: (gst_avi_demux_get_type),
+ (gst_avi_demux_class_init), (gst_avi_demux_init),
+ (gst_avi_demux_reset), (gst_avi_demux_src_convert),
+ (gst_avi_demux_handle_src_query), (gst_avi_demux_handle_src_event),
+ (gst_avi_demux_parse_file_header), (gst_avi_demux_stream_init),
+ (gst_avi_demux_parse_avih), (gst_avi_demux_parse_superindex),
+ (gst_avi_demux_parse_subindex), (gst_avi_demux_read_subindexes),
+ (gst_avi_demux_parse_stream), (gst_avi_demux_parse_odml),
+ (gst_avi_demux_parse_index), (gst_avi_demux_stream_index),
+ (gst_avi_demux_stream_scan), (gst_avi_demux_massage_index),
+ (gst_avi_demux_stream_header), (gst_avi_demux_handle_seek),
+ (gst_avi_demux_process_next_entry), (gst_avi_demux_stream_data),
+ (gst_avi_demux_loop), (gst_avi_demux_sink_activate):
+ * gst/avi/gstavidemux.h:
+ Port to changed RIFF API, port to 0.9, add locking. Add gtk-doc
+ comments to some relevant functions. Seeking is weird, works
+ otherwise. Some parts are still disabled.
+
2005-02-01 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/gnomevfs/Makefile.am:
diff --git a/examples/seeking/seek.c b/examples/seeking/seek.c
index f171d0c1a..4ba2f34c6 100644
--- a/examples/seeking/seek.c
+++ b/examples/seeking/seek.c
@@ -20,7 +20,7 @@ static guint update_id;
static gulong changed_id;
//#define SOURCE "gnomevfssrc"
-#define SOURCE "filesrc"
+#define SOURCE "gnomevfssrc"
#define UPDATE_INTERVAL 500
@@ -422,6 +422,71 @@ make_vorbis_theora_pipeline (const gchar * location)
}
static GstElement *
+make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
+{
+ GstElement *pipeline, *audio_bin, *video_bin;
+ GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
+ GstElement *audiosink, *videosink;
+ GstElement *a_queue, *v_queue;
+ GstPad *seekable;
+
+ pipeline = gst_pipeline_new ("app");
+
+ src = gst_element_factory_make_or_warn (SOURCE, "src");
+ g_object_set (G_OBJECT (src), "location", location, NULL);
+
+ demux = gst_element_factory_make_or_warn ("avidemux", "demux");
+
+ gst_bin_add (GST_BIN (pipeline), src);
+ gst_bin_add (GST_BIN (pipeline), demux);
+ gst_element_link (src, demux);
+
+ audio_bin = gst_bin_new ("a_decoder_bin");
+ a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
+ a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
+ a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
+ audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
+
+ gst_element_link (a_queue, a_decoder);
+ gst_element_link (a_decoder, a_convert);
+ gst_element_link (a_convert, audiosink);
+
+ gst_bin_add (GST_BIN (audio_bin), a_queue);
+ gst_bin_add (GST_BIN (audio_bin), a_decoder);
+ gst_bin_add (GST_BIN (audio_bin), a_convert);
+ gst_bin_add (GST_BIN (audio_bin), audiosink);
+
+ gst_bin_add (GST_BIN (pipeline), audio_bin);
+
+ setup_dynamic_link (demux, NULL, gst_element_get_pad (a_queue, "sink"), NULL);
+
+ video_bin = gst_bin_new ("v_decoder_bin");
+ v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
+ v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
+ v_convert =
+ gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
+ videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
+ gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
+
+ gst_bin_add (GST_BIN (video_bin), v_queue);
+ gst_bin_add (GST_BIN (video_bin), v_decoder);
+ gst_bin_add (GST_BIN (video_bin), v_convert);
+ gst_bin_add (GST_BIN (video_bin), videosink);
+
+ gst_bin_add (GST_BIN (pipeline), video_bin);
+
+ setup_dynamic_link (demux, NULL, gst_element_get_pad (v_queue, "sink"), NULL);
+
+ seekable = gst_element_get_pad (a_decoder, "src");
+ seekable_pads = g_list_prepend (seekable_pads, seekable);
+ rate_pads = g_list_prepend (rate_pads, seekable);
+ rate_pads =
+ g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
+
+ return pipeline;
+}
+
+static GstElement *
make_mp3_pipeline (const gchar * location)
{
GstElement *pipeline;
@@ -1043,6 +1108,7 @@ static Pipeline pipelines[] = {
{"vorbis", make_vorbis_pipeline},
{"theora", make_theora_pipeline},
{"ogg/v/t", make_vorbis_theora_pipeline},
+ {"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
{"sid", make_sid_pipeline},
{"flac", make_flac_pipeline},
{"wav", make_wav_pipeline},
diff --git a/gst/avi/Makefile.am b/gst/avi/Makefile.am
index cbea2b3ad..89b5fb67a 100644
--- a/gst/avi/Makefile.am
+++ b/gst/avi/Makefile.am
@@ -2,12 +2,12 @@ plugin_LTLIBRARIES = libgstavi.la
libgstavi_la_SOURCES = \
gstavi.c \
- gstavidemux.c \
- gstavimux.c
+ gstavidemux.c
+
+#gstavimux.c
noinst_HEADERS = \
avi-ids.h \
- gstavimux.h \
gstavidemux.h
libgstavi_la_CFLAGS = $(GST_CFLAGS)
diff --git a/gst/avi/gstavi.c b/gst/avi/gstavi.c
index 4ab32d7b4..8b3d99352 100644
--- a/gst/avi/gstavi.c
+++ b/gst/avi/gstavi.c
@@ -39,10 +39,9 @@ plugin_init (GstPlugin * plugin)
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif /* ENABLE_NLS */
- return (gst_element_register (plugin, "avidemux",
- GST_RANK_PRIMARY,
- GST_TYPE_AVI_DEMUX) &&
- gst_element_register (plugin, "avimux", GST_RANK_NONE, GST_TYPE_AVIMUX));
+ return (gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY, GST_TYPE_AVI_DEMUX) /*&&
+ gst_element_register (plugin, "avimux", GST_RANK_NONE, GST_TYPE_AVIMUX) */
+ );
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 367e4b326..84fd4a409 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -31,6 +31,8 @@
GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
#define GST_CAT_DEFAULT avidemux_debug
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
+
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@@ -42,10 +44,6 @@ static void gst_avi_demux_class_init (GstAviDemuxClass * klass);
static void gst_avi_demux_init (GstAviDemux * avi);
static void gst_avi_demux_reset (GstAviDemux * avi);
-static void gst_avi_demux_loop (GstElement * element);
-
-static gboolean gst_avi_demux_send_event (GstElement * element,
- GstEvent * event);
static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad);
static gboolean gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event);
@@ -57,9 +55,13 @@ static gboolean gst_avi_demux_src_convert (GstPad * pad,
GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
+static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi);
+static void gst_avi_demux_loop (GstPad * pad);
+static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad,
+ GstActivateMode mode);
static GstElementStateReturn gst_avi_demux_change_state (GstElement * element);
-static GstRiffReadClass *parent_class = NULL;
+static GstElementClass *parent_class = NULL;
GType
gst_avi_demux_get_type (void)
@@ -80,7 +82,7 @@ gst_avi_demux_get_type (void)
};
avi_demux_type =
- g_type_register_static (GST_TYPE_RIFF_READ,
+ g_type_register_static (GST_TYPE_ELEMENT,
"GstAviDemux", &avi_demux_info, 0);
}
@@ -120,33 +122,26 @@ gst_avi_demux_base_init (GstAviDemuxClass * klass)
static void
gst_avi_demux_class_init (GstAviDemuxClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
0, "Demuxer for AVI streams");
- parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
+ parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
gstelement_class->change_state = gst_avi_demux_change_state;
- gstelement_class->send_event = gst_avi_demux_send_event;
}
static void
gst_avi_demux_init (GstAviDemux * avi)
{
- GST_FLAG_SET (avi, GST_ELEMENT_EVENT_AWARE);
-
avi->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sink_templ),
"sink");
+ gst_pad_set_loop_function (avi->sinkpad, gst_avi_demux_loop);
+ gst_pad_set_activate_function (avi->sinkpad, gst_avi_demux_sink_activate);
gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
- GST_RIFF_READ (avi)->sinkpad = avi->sinkpad;
- gst_element_set_loop_function (GST_ELEMENT (avi), gst_avi_demux_loop);
gst_avi_demux_reset (avi);
avi->index_entries = NULL;
@@ -160,8 +155,13 @@ gst_avi_demux_reset (GstAviDemux * avi)
for (i = 0; i < avi->num_streams; i++) {
g_free (avi->stream[i].strh);
+ g_free (avi->stream[i].strf.data);
+ g_free (avi->stream[i].name);
+ if (avi->stream[i].initdata)
+ gst_buffer_unref (avi->stream[i].initdata);
+ if (avi->stream[i].extradata)
+ gst_buffer_unref (avi->stream[i].extradata);
gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad);
- gst_caps_free (avi->stream[i].caps);
}
memset (&avi->stream, 0, sizeof (avi->stream));
@@ -170,18 +170,15 @@ gst_avi_demux_reset (GstAviDemux * avi)
avi->num_a_streams = 0;
avi->state = GST_AVI_DEMUX_START;
- avi->level_up = 0;
+ avi->offset = 0;
- if (avi->index_entries) {
- g_free (avi->index_entries);
- avi->index_entries = NULL;
- }
+ g_free (avi->index_entries);
+ avi->index_entries = NULL;
avi->index_size = 0;
avi->index_offset = 0;
avi->current_entry = 0;
-
- avi->num_frames = 0;
- avi->us_per_frame = 0;
+ g_free (avi->avih);
+ avi->avih = NULL;
avi->seek_offset = (guint64) - 1;
}
@@ -304,6 +301,8 @@ gst_avi_demux_src_convert (GstPad * pad,
/*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad)); */
avi_stream_context *stream = gst_pad_get_element_private (pad);
+ if (!stream->strh || !stream->strf.data)
+ return FALSE;
if (stream->strh->type == GST_RIFF_FCC_vids &&
(src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
return FALSE;
@@ -312,7 +311,7 @@ gst_avi_demux_src_convert (GstPad * pad,
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
- *dest_value = src_value * stream->bitrate / GST_SECOND;
+ *dest_value = src_value * stream->strf.auds->av_bps / GST_SECOND;
break;
case GST_FORMAT_DEFAULT:
*dest_value = src_value * stream->strh->rate /
@@ -326,7 +325,11 @@ gst_avi_demux_src_convert (GstPad * pad,
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_TIME:
- *dest_value = ((gfloat) src_value) * GST_SECOND / stream->bitrate;
+ if (stream->strf.auds->av_bps != 0) {
+ *dest_value = ((gfloat) src_value) * GST_SECOND /
+ stream->strf.auds->av_bps;
+ } else
+ res = FALSE;
break;
default:
res = FALSE;
@@ -373,6 +376,9 @@ gst_avi_demux_handle_src_query (GstPad * pad,
/*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad)); */
avi_stream_context *stream = gst_pad_get_element_private (pad);
+ if (!stream->strh || !stream->strf.data)
+ return FALSE;
+
switch (type) {
case GST_QUERY_TOTAL:
switch (*format) {
@@ -409,13 +415,13 @@ gst_avi_demux_handle_src_query (GstPad * pad,
if (!stream->strh->samplesize) {
*value = GST_SECOND * stream->current_frame *
stream->strh->scale / stream->strh->rate;
- } else if (stream->bitrate != 0) {
+ } else if (stream->strf.auds->av_bps != 0) {
*value = ((gfloat) stream->current_byte) * GST_SECOND /
- stream->bitrate;
+ stream->strf.auds->av_bps;
} else if (stream->total_frames != 0 && stream->total_bytes != 0) {
/* calculate timestamps based on video size */
- guint64 len = demux->us_per_frame * demux->num_frames *
- GST_USECOND;
+ guint64 len = demux->avih->us_frame *
+ demux->avih->tot_frames * GST_USECOND;
if (!stream->strh->samplesize)
*value = len * stream->current_frame / stream->total_frames;
@@ -429,7 +435,7 @@ gst_avi_demux_handle_src_query (GstPad * pad,
*value = ((gfloat) stream->current_frame * stream->strh->scale *
GST_SECOND / stream->strh->rate);
} else {
- *value = stream->current_frame * demux->us_per_frame *
+ *value = stream->current_frame * demux->avih->us_frame *
GST_USECOND;
}
}
@@ -457,43 +463,6 @@ gst_avi_demux_handle_src_query (GstPad * pad,
return res;
}
-static GstCaps *
-gst_avi_demux_src_getcaps (GstPad * pad)
-{
- avi_stream_context *stream = gst_pad_get_element_private (pad);
-
- return gst_caps_copy (stream->caps);
-}
-
-static gboolean
-gst_avi_demux_send_event (GstElement * element, GstEvent * event)
-{
- const GList *pads;
-
- pads = gst_element_get_pad_list (element);
-
- while (pads) {
- GstPad *pad = GST_PAD (pads->data);
-
- if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
- /* we ref the event here as we might have to try again if the event
- * failed on this pad */
- gst_event_ref (event);
- if (gst_avi_demux_handle_src_event (pad, event)) {
- gst_event_unref (event);
-
- return TRUE;
- }
- }
-
- pads = g_list_next (pads);
- }
-
- gst_event_unref (event);
-
- return FALSE;
-}
-
static const GstEventMask *
gst_avi_demux_get_event_mask (GstPad * pad)
{
@@ -512,15 +481,19 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
avi_stream_context *stream;
- if (!avi->index_entries)
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, avi,
+ "have event type %d: %p on src pad", GST_EVENT_TYPE (event), event);
+ if (!avi->index_entries) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_EVENT, avi, "no index entries, returning");
return FALSE;
+ }
stream = gst_pad_get_element_private (pad);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
- GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event),
- stream->strh->type);
+ GST_DEBUG_OBJECT (avi, "seek format %d, %08x",
+ GST_EVENT_SEEK_FORMAT (event), stream->strh->type);
switch (GST_EVENT_SEEK_FORMAT (event)) {
case GST_FORMAT_BYTES:
@@ -530,12 +503,8 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
guint32 flags;
- /* no seek on audio yet */
- if (stream->strh->type == GST_RIFF_FCC_auds) {
- res = FALSE;
- goto done;
- }
- GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
+ GST_DEBUG_OBJECT (avi, "seeking to %" G_GINT64_FORMAT,
+ desired_offset);
flags = GST_RIFF_IF_KEYFRAME;
switch (GST_EVENT_SEEK_FORMAT (event)) {
@@ -559,13 +528,14 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
avi->seek_flush =
(GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH);
avi->seek_entry = entry->index_nr;
- GST_DEBUG ("Will seek to entry %d", avi->seek_entry);
+ GST_DEBUG_OBJECT (avi, "Will seek to entry %d", avi->seek_entry);
+ res = gst_avi_demux_handle_seek (avi);
} else {
- GST_DEBUG ("no index entry found for format=%d value=%"
+ GST_DEBUG_OBJECT (avi, "no index entry found for format=%d value=%"
G_GINT64_FORMAT, GST_EVENT_SEEK_FORMAT (event), desired_offset);
res = FALSE;
}
- GST_LOG ("seek done\n");
+ GST_LOG ("seek done");
break;
}
default:
@@ -578,126 +548,159 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
break;
}
-done:
gst_event_unref (event);
return res;
}
-/*
- * "Open" a RIFF file.
+/**
+ * gst_avi_demux_parse_file_header:
+ * @element: caller element (used for errors/debug).
+ * @buf: input data to be used for parsing.
+ *
+ * "Open" a RIFF/AVI file. The buffer should be at least 12
+ * bytes long. Discards buffer after use.
+ *
+ * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
+ * Throws an error, caller should error out (fatal).
*/
static gboolean
-gst_avi_demux_stream_init (GstAviDemux * avi)
+gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
guint32 doctype;
- if (!gst_riff_read_header (riff, &doctype))
+ if (!gst_riff_parse_file_header (element, buf, &doctype))
return FALSE;
+
if (doctype != GST_RIFF_RIFF_AVI) {
- GST_ELEMENT_ERROR (avi, STREAM, WRONG_TYPE, (NULL), (NULL));
+ GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
+ ("File is not an AVI file: " GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (doctype)));
return FALSE;
}
return TRUE;
}
-/*
- * Read 'avih' header.
+static GstFlowReturn
+gst_avi_demux_stream_init (GstAviDemux * avi)
+{
+ GstFlowReturn res;
+ GstBuffer *buf = NULL;
+
+ if ((res = gst_pad_pull_range (avi->sinkpad,
+ avi->offset, 12, &buf)) != GST_FLOW_OK)
+ return res;
+ else if (!gst_avi_demux_parse_file_header (GST_ELEMENT (avi), buf))
+ return GST_FLOW_ERROR;
+
+ avi->offset += 12;
+
+ return GST_FLOW_OK;
+}
+
+/**
+ * gst_avi_demux_parse_avih:
+ * @element: caller element (used for errors/debug).
+ * @buf: input data to be used for parsing.
+ * @avih: pointer to structure (filled in by function) containing
+ * stream information (such as flags, number of streams, etc.).
+ *
+ * Read 'avih' header. Discards buffer after use.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Throws an error if
+ * the header is invalid. The caller should error out
+ * (fatal).
*/
static gboolean
-gst_avi_demux_stream_avih (GstAviDemux * avi,
- guint32 * flags, guint32 * streams)
+gst_avi_demux_parse_avih (GstElement * element,
+ GstBuffer * buf, gst_riff_avih ** _avih)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag;
- GstBuffer *buf;
- gst_riff_avih avih, *_avih;
+ gst_riff_avih *avih;
- if (!gst_riff_read_data (riff, &tag, &buf))
- return FALSE;
-
- if (tag != GST_RIFF_TAG_avih) {
- g_warning ("Not a avih chunk");
- gst_buffer_unref (buf);
- return FALSE;
- }
- if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) {
- g_warning ("Too small avih (%d available, %d needed)",
- GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih));
- gst_buffer_unref (buf);
+ if (!buf || GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) {
+ GST_ELEMENT_ERROR (element, STREAM, INVALID_DATA, (NULL),
+ ("Too small avih (%d available, %d needed)",
+ GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih)));
+ if (buf)
+ gst_buffer_unref (buf);
return FALSE;
}
- _avih = (gst_riff_avih *) GST_BUFFER_DATA (buf);
- avih.us_frame = GUINT32_FROM_LE (_avih->us_frame);
- avih.max_bps = GUINT32_FROM_LE (_avih->max_bps);
- avih.pad_gran = GUINT32_FROM_LE (_avih->pad_gran);
- avih.flags = GUINT32_FROM_LE (_avih->flags);
- avih.tot_frames = GUINT32_FROM_LE (_avih->tot_frames);
- avih.init_frames = GUINT32_FROM_LE (_avih->init_frames);
- avih.streams = GUINT32_FROM_LE (_avih->streams);
- avih.bufsize = GUINT32_FROM_LE (_avih->bufsize);
- avih.width = GUINT32_FROM_LE (_avih->width);
- avih.height = GUINT32_FROM_LE (_avih->height);
- avih.scale = GUINT32_FROM_LE (_avih->scale);
- avih.rate = GUINT32_FROM_LE (_avih->rate);
- avih.start = GUINT32_FROM_LE (_avih->start);
- avih.length = GUINT32_FROM_LE (_avih->length);
+ avih = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
+ avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
+ avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
+ avih->flags = GUINT32_FROM_LE (avih->flags);
+ avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
+ avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
+ avih->streams = GUINT32_FROM_LE (avih->streams);
+ avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
+ avih->width = GUINT32_FROM_LE (avih->width);
+ avih->height = GUINT32_FROM_LE (avih->height);
+ avih->scale = GUINT32_FROM_LE (avih->scale);
+ avih->rate = GUINT32_FROM_LE (avih->rate);
+ avih->start = GUINT32_FROM_LE (avih->start);
+ avih->length = GUINT32_FROM_LE (avih->length);
+#endif
/* debug stuff */
- GST_INFO ("avih tag found:");
- GST_INFO (" us_frame %u", avih.us_frame);
- GST_INFO (" max_bps %u", avih.max_bps);
- GST_INFO (" pad_gran %u", avih.pad_gran);
- GST_INFO (" flags 0x%08x", avih.flags);
- GST_INFO (" tot_frames %u", avih.tot_frames);
- GST_INFO (" init_frames %u", avih.init_frames);
- GST_INFO (" streams %u", avih.streams);
- GST_INFO (" bufsize %u", avih.bufsize);
- GST_INFO (" width %u", avih.width);
- GST_INFO (" height %u", avih.height);
- GST_INFO (" scale %u", avih.scale);
- GST_INFO (" rate %u", avih.rate);
- GST_INFO (" start %u", avih.start);
- GST_INFO (" length %u", avih.length);
-
- avi->num_frames = avih.tot_frames;
- avi->us_per_frame = avih.us_frame;
- *streams = avih.streams;
- *flags = avih.flags;
-
+ GST_INFO_OBJECT (element, "avih tag found:");
+ GST_INFO_OBJECT (element, " us_frame %u", avih->us_frame);
+ GST_INFO_OBJECT (element, " max_bps %u", avih->max_bps);
+ GST_INFO_OBJECT (element, " pad_gran %u", avih->pad_gran);
+ GST_INFO_OBJECT (element, " flags 0x%08x", avih->flags);
+ GST_INFO_OBJECT (element, " tot_frames %u", avih->tot_frames);
+ GST_INFO_OBJECT (element, " init_frames %u", avih->init_frames);
+ GST_INFO_OBJECT (element, " streams %u", avih->streams);
+ GST_INFO_OBJECT (element, " bufsize %u", avih->bufsize);
+ GST_INFO_OBJECT (element, " width %u", avih->width);
+ GST_INFO_OBJECT (element, " height %u", avih->height);
+ GST_INFO_OBJECT (element, " scale %u", avih->scale);
+ GST_INFO_OBJECT (element, " rate %u", avih->rate);
+ GST_INFO_OBJECT (element, " start %u", avih->start);
+ GST_INFO_OBJECT (element, " length %u", avih->length);
+
+ *_avih = avih;
gst_buffer_unref (buf);
return TRUE;
}
-/*
- * Read superindex/subindex (openDML-2).
+/**
+ * gst_avi_demux_parse_superindex:
+ * @element: caller element (used for debugging/errors).
+ * @buf: input data to use for parsing.
+ * @locations: locations in the file (byte-offsets) that contain
+ * the actual indexes (see get_avi_demux_parse_subindex()).
+ * The array ends with GST_BUFFER_OFFSET_NONE.
+ *
+ * Reads superindex (openDML-2 spec stuff) from the provided data.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
+ * on error, but they are not fatal.
*/
static gboolean
-gst_avi_demux_read_superindex (GstAviDemux * avi,
- gint stream_nr, guint64 ** locations)
+gst_avi_demux_parse_superindex (GstElement * element,
+ GstBuffer * buf, guint64 ** _indexes)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag;
- GstBuffer *buf;
- guint8 *data;
+ guint8 *data = GST_BUFFER_DATA (buf);
gint bpe = 16, num, i;
guint64 *indexes;
- if (!gst_riff_read_data (riff, &tag, &buf))
- return FALSE;
- data = GST_BUFFER_DATA (buf);
- if (tag != GST_MAKE_FOURCC ('i', 'n', 'd', 'x') &&
- tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream_nr / 10,
- '0' + stream_nr % 10)) {
- g_warning ("Not an indx/ix## chunk");
- gst_buffer_unref (buf);
+ *_indexes = NULL;
+
+ if (!buf || GST_BUFFER_SIZE (buf) < 24) {
+ GST_ERROR_OBJECT (element,
+ "Not enough data to parse superindex (%d available, %d needed)",
+ GST_BUFFER_SIZE (buf), 24);
+ if (buf)
+ gst_buffer_unref (buf);
return FALSE;
}
@@ -706,7 +709,8 @@ gst_avi_demux_read_superindex (GstAviDemux * avi,
* either frame or field (and we don't care). */
if (GST_READ_UINT16_LE (data) != 4 ||
(data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
- GST_WARNING ("Superindex for stream %d has unexpected "
+ GST_WARNING_OBJECT (element,
+ "Superindex for stream %d has unexpected "
"size_entry %d (bytes) or flags 0x%02x/0x%02x",
GST_READ_UINT16_LE (data), data[2], data[3]);
bpe = GST_READ_UINT16_LE (data) * 4;
@@ -719,538 +723,473 @@ gst_avi_demux_read_superindex (GstAviDemux * avi,
break;
indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
}
- indexes[i] = 0;
- *locations = indexes;
+ indexes[i] = GST_BUFFER_OFFSET_NONE;
+ *_indexes = indexes;
gst_buffer_unref (buf);
return TRUE;
}
+/**
+ * gst_avi_demux_parse_subindex:
+ * @element: caller element (used for errors/debug).
+ * @buf: input data to use for parsing.
+ * @stream: stream context.
+ * @entries_list: a list (returned by the function) containing all the
+ * indexes parsed in this specific subindex. The first
+ * entry is also a pointer to allocated memory that needs
+ * to be freeĀ“ed. May be NULL if no supported indexes were
+ * found.
+ *
+ * Reads superindex (openDML-2 spec stuff) from the provided data.
+ * The buffer will be discarded after use.
+ *
+ * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
+ * throw an error, caller should bail out asap.
+ */
+
static gboolean
-gst_avi_demux_read_subindexes (GstAviDemux * avi,
- GList ** index, GList ** alloc_list)
+gst_avi_demux_parse_subindex (GstElement * element,
+ GstBuffer * buf, avi_stream_context * stream, GList ** _entries_list)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint64 pos = gst_bytestream_tell (riff->bs),
- length = gst_bytestream_length (riff->bs), baseoff;
- GstEvent *event;
- GList *list = NULL;
+ guint8 *data = GST_BUFFER_DATA (buf);
+ gint bpe, num, x;
+ guint64 baseoff;
gst_avi_index_entry *entries, *entry;
- guint32 tag;
- GstBuffer *buf;
- guint8 *data;
+ GList *entries_list = NULL;
GstFormat format = GST_FORMAT_TIME;
- gint bpe, num, x, i, n;
- for (n = 0; n < avi->num_streams; n++) {
- avi_stream_context *stream = &avi->stream[n];
+ /* check size */
+ if (!buf || GST_BUFFER_SIZE (buf) < 24) {
+ GST_ERROR_OBJECT (element,
+ "Not enough data to parse subindex (%d available, %d needed)",
+ GST_BUFFER_SIZE (buf), 24);
+ if (buf)
+ gst_buffer_unref (buf);
+ *_entries_list = NULL;
+ return TRUE; /* continue */
+ }
- for (i = 0; stream->indexes[i] != 0; i++) {
- /* eos check again */
- if (stream->indexes[i] + 8 >= length) {
- GST_WARNING ("Subindex %d for stream %d doesn't exist", i, n);
- continue;
- }
+ /* We don't support index-data yet */
+ if (data[3] & 0x80) {
+ GST_ELEMENT_ERROR (element, STREAM, NOT_IMPLEMENTED, (NULL),
+ ("Subindex-is-data is not implemented"));
+ gst_buffer_unref (buf);
+ return FALSE;
+ }
- /* seek to that point */
- if (!(event = gst_riff_read_seek (riff, stream->indexes[i]))) {
- g_list_free (list);
- return FALSE;
- }
- gst_event_unref (event);
- if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) {
- g_list_free (list);
- return FALSE;
- }
+ /* check type of index. The opendml2 specs state that
+ * there should be 4 dwords per array entry. Type can be
+ * either frame or field (and we don't care). */
+ bpe = (data[2] & 0x01) ? 12 : 8;
+ if (GST_READ_UINT16_LE (data) != bpe / 4 ||
+ (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
+ GST_WARNING_OBJECT (element,
+ "Superindex for stream %d has unexpected "
+ "size_entry %d (bytes) or flags 0x%02x/0x%02x",
+ GST_READ_UINT16_LE (data), data[2], data[3]);
+ bpe = GST_READ_UINT16_LE (data) * 4;
+ }
+ num = GST_READ_UINT32_LE (&data[4]);
+ baseoff = GST_READ_UINT64_LE (&data[12]);
- /* eos check again */
- if (GST_READ_UINT32_LE (&data[4]) + gst_bytestream_tell (riff->bs) >
- length) {
- GST_WARNING ("Subindex %d for stream %d lies outside file", i, n);
- continue;
- }
+ entries = g_new (gst_avi_index_entry, num);
+ for (x = 0; x < num; x++) {
+ entry = &entries[x];
- /* now read */
- if (!gst_riff_read_data (riff, &tag, &buf))
- return FALSE;
- data = GST_BUFFER_DATA (buf);
- if (tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
- '0' + stream->num % 10)) {
- GST_WARNING ("Not an ix## chunk (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS (tag));
- gst_buffer_unref (buf);
- continue;
- }
+ if (GST_BUFFER_SIZE (buf) < 24 + bpe * (x + 1))
+ break;
- /* We don't support index-data yet */
- if (data[3] & 0x80) {
- GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
- ("Subindex-is-data is not implemented"));
- return FALSE;
- }
+ /* fill in */
+ entry->offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * x]);
+ entry->size = GST_READ_UINT32_LE (&data[24 + bpe * x + 4]);
+ entry->flags = (entry->size & 0x80000000) ? 0 : GST_RIFF_IF_KEYFRAME;
+ entry->size &= ~0x80000000;
+ entry->index_nr = x;
+ entry->stream_nr = stream->num;
- /* check type of index. The opendml2 specs state that
- * there should be 4 dwords per array entry. Type can be
- * either frame or field (and we don't care). */
- bpe = (data[2] & 0x01) ? 12 : 8;
- if (GST_READ_UINT16_LE (data) != bpe / 4 ||
- (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
- GST_WARNING ("Superindex for stream %d has unexpected "
- "size_entry %d (bytes) or flags 0x%02x/0x%02x",
- GST_READ_UINT16_LE (data), data[2], data[3]);
- bpe = GST_READ_UINT16_LE (data) * 4;
- }
- num = GST_READ_UINT32_LE (&data[4]);
- baseoff = GST_READ_UINT64_LE (&data[12]);
+ /* timestamps */
+ if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
+ /* constant rate stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes, &format, &entry->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes + entry->size, &format, &entry->dur);
+ } else {
+ /* VBR stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames, &format, &entry->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames + 1, &format, &entry->dur);
+ }
+ entry->dur -= entry->ts;
- entries = g_new (gst_avi_index_entry, num);
- *alloc_list = g_list_append (*alloc_list, entries);
- for (x = 0; x < num; x++) {
- entry = &entries[x];
+ /* stream position */
+ entry->bytes_before = stream->total_bytes;
+ stream->total_bytes += entry->size;
+ entry->frames_before = stream->total_frames;
+ stream->total_frames++;
- if (GST_BUFFER_SIZE (buf) < 24 + bpe * (x + 1))
- break;
+ entries_list = g_list_prepend (entries_list, entry);
+ }
- /* fill in */
- entry->offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * x]);
- entry->size = GST_READ_UINT32_LE (&data[24 + bpe * x + 4]);
- entry->flags = (entry->size & 0x80000000) ? 0 : GST_RIFF_IF_KEYFRAME;
- entry->size &= ~0x80000000;
- entry->index_nr = x;
- entry->stream_nr = stream->num;
-
- /* timestamps */
- if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
- /* constant rate stream */
- gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
- stream->total_bytes, &format, &entry->ts);
- gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
- stream->total_bytes + entry->size, &format, &entry->dur);
- } else {
- /* VBR stream */
- gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
- stream->total_frames, &format, &entry->ts);
- gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
- stream->total_frames + 1, &format, &entry->dur);
- }
- entry->dur -= entry->ts;
+ GST_LOG_OBJECT (element, "Read %d index entries", x);
- /* stream position */
- entry->bytes_before = stream->total_bytes;
- stream->total_bytes += entry->size;
- entry->frames_before = stream->total_frames;
- stream->total_frames++;
+ gst_buffer_unref (buf);
- list = g_list_prepend (list, entry);
- }
+ if (x > 0) {
+ *_entries_list = g_list_reverse (entries_list);
+ } else {
+ *_entries_list = NULL;
+ g_free (entries);
+ }
- GST_LOG ("Read %d index entries in subindex %d for stream %d "
- "at location %" G_GUINT64_FORMAT, num, i, n, stream->indexes[i]);
+ return TRUE;
+}
- gst_buffer_unref (buf);
+static void
+gst_avi_demux_read_subindexes (GstAviDemux * avi,
+ GList ** index, GList ** alloc_list)
+{
+ GList *list;
+ guint32 tag;
+ GstBuffer *buf;
+ gint i, n;
+
+ for (n = 0; n < avi->num_streams; n++) {
+ avi_stream_context *stream = &avi->stream[n];
+
+ for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
+ if (gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad,
+ &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
+ continue;
+ else if (tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
+ '0' + stream->num % 10)) {
+ GST_ERROR_OBJECT (GST_ELEMENT (avi),
+ "Not an ix## chunk (" GST_FOURCC_FORMAT ")", GST_FOURCC_ARGS (tag));
+ gst_buffer_unref (buf);
+ continue;
+ }
+
+ if (!gst_avi_demux_parse_subindex (GST_ELEMENT (avi), buf, stream, &list))
+ continue;
+ if (list) {
+ *alloc_list = g_list_append (*alloc_list, list->data);
+ *index = g_list_concat (*index, list);
+ }
}
g_free (stream->indexes);
stream->indexes = NULL;
}
-
- /* seek back */
- if (!(event = gst_riff_read_seek (riff, pos))) {
- g_list_free (list);
- return FALSE;
- }
- gst_event_unref (event);
- *index = g_list_reverse (list);
-
- return TRUE;
}
-/*
- * Add a stream.
+/**
+ * gst_avi_demux_parse_stream:
+ * @element: calling element (used for debugging/errors).
+ * @buf: input buffer used to parse the stream.
+ *
+ * Parses all subchunks in a strl chunk (which defines a single
+ * stream). Discards the buffer after use. This function will
+ * increment the stream counter internally.
+ *
+ * Returns: whether the stream was identified successfully.
+ * Errors are not fatal. It does indicate the stream
+ * was skipped.
*/
static gboolean
-gst_avi_demux_add_stream (GstAviDemux * avi)
+gst_avi_demux_parse_stream (GstElement * element, GstBuffer * buf)
{
- GstElementClass *klass = GST_ELEMENT_GET_CLASS (avi);
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag;
- gst_riff_strh *strh;
- GstBuffer *extradata = NULL, *initdata = NULL;
- gchar *name = NULL, *padname = NULL;
+ GstAviDemux *avi = GST_AVI_DEMUX (element);
+ avi_stream_context *stream = &avi->stream[avi->num_streams];
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+ GstPadTemplate *templ;
+ GstBuffer *sub = NULL;
+ guint offset = 4;
+ guint32 tag = 0;
+ gchar *codec_name = NULL, *padname = NULL;
+ const gchar *tag_name;
GstCaps *caps = NULL;
- GstPadTemplate *templ = NULL;
GstPad *pad;
- avi_stream_context *stream;
- gint blockalign = 0, bitrate = 0;
- guint64 *locations = NULL;
- union
- {
- gst_riff_strf_vids *vids;
- gst_riff_strf_auds *auds;
- gst_riff_strf_iavs *iavs;
- }
- strf;
-
- /* the stream starts with a 'strh' header */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_strh) {
- g_warning ("Invalid stream header (no strh at begin)");
- goto skip_stream;
- }
- if (!gst_riff_read_strh (riff, &strh))
- return FALSE;
- /* then comes a 'strf' of that specific type */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_strf) {
- GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
- ("Invalid AVI header (no strf as second tag)"));
- goto skip_stream;
- }
- switch (strh->type) {
- case GST_RIFF_FCC_vids:
- if (!gst_riff_read_strf_vids_with_data (riff, &strf.vids, &extradata))
- return FALSE;
- break;
- case GST_RIFF_FCC_auds:
- if (!gst_riff_read_strf_auds_with_data (riff, &strf.auds, &extradata))
- return FALSE;
- break;
- case GST_RIFF_FCC_iavs:
- if (!gst_riff_read_strf_iavs (riff, &strf.iavs))
- return FALSE;
- break;
- default:
- g_warning ("Unknown stream type " GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (strh->type));
- goto skip_stream;
- }
+ GST_DEBUG_OBJECT (element, "Parsing stream");
+
+ /* read strh */
+ if (!buf || !gst_riff_parse_chunk (element, buf, &offset, &tag, &sub) ||
+ tag != GST_RIFF_TAG_strh) {
+ GST_ERROR_OBJECT (element,
+ "Failed to find strh chunk (tag: " GST_FOURCC_FORMAT ")",
+ buf ? GST_BUFFER_SIZE (buf) : 0, GST_FOURCC_ARGS (tag));
+ goto fail;
+ } else if (!gst_riff_parse_strh (element, sub, &stream->strh))
+ goto fail;
+
+ /* read strf */
+ if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub) ||
+ tag != GST_RIFF_TAG_strf) {
+ GST_ERROR_OBJECT (element,
+ "Failed to find strh chunk (size: %d, tag: "
+ GST_FOURCC_FORMAT ")", buf ? GST_BUFFER_SIZE (buf) : 0,
+ GST_FOURCC_ARGS (tag));
+ goto fail;
+ } else {
+ gboolean res = FALSE;
- /* read other things */
- while (TRUE) {
- if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
- return FALSE;
- else if (avi->level_up) {
- avi->level_up--;
- break;
+ switch (stream->strh->type) {
+ case GST_RIFF_FCC_vids:
+ res = gst_riff_parse_strf_vids (element, sub,
+ &stream->strf.vids, &stream->extradata);
+ break;
+ case GST_RIFF_FCC_auds:
+ res = gst_riff_parse_strf_auds (element, sub,
+ &stream->strf.auds, &stream->extradata);
+ break;
+ case GST_RIFF_FCC_iavs:
+ res = gst_riff_parse_strf_iavs (element, sub,
+ &stream->strf.iavs, &stream->extradata);
+ break;
+ default:
+ GST_ERROR_OBJECT (element,
+ "DonĀ“t know how to handle stream type " GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (stream->strh->type));
+ break;
}
+ if (!res)
+ goto fail;
+ }
+
+ /* read strd/strn */
+ while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
switch (tag) {
case GST_RIFF_TAG_strd:
- if (initdata)
- gst_buffer_unref (initdata);
- if (!gst_riff_read_data (riff, &tag, &initdata))
- return FALSE;
+ if (stream->initdata)
+ gst_buffer_unref (stream->initdata);
+ stream->initdata = sub;
break;
-
case GST_RIFF_TAG_strn:
- g_free (name);
- if (!gst_riff_read_ascii (riff, &tag, &name))
- return FALSE;
+ g_free (stream->name);
+ stream->name = g_new (gchar, GST_BUFFER_SIZE (sub));
+ memcpy (stream->name, GST_BUFFER_DATA (sub), GST_BUFFER_SIZE (sub));
+ stream->name[GST_BUFFER_SIZE (sub)] = '\0';
+ gst_buffer_unref (sub);
break;
-
default:
if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
- tag == GST_MAKE_FOURCC ('i', 'x', avi->num_streams / 10,
- avi->num_streams % 10)) {
- g_free (locations);
- if (!gst_avi_demux_read_superindex (avi,
- avi->num_streams, &locations))
- return FALSE;
+ tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
+ '0' + avi->num_streams % 10)) {
+ g_free (stream->indexes);
+ gst_avi_demux_parse_superindex (element, sub, &stream->indexes);
break;
}
- GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
+ GST_WARNING_OBJECT (element,
+ "Unknown stream header tag " GST_FOURCC_FORMAT ", ignoring",
GST_FOURCC_ARGS (tag));
/* fall-through */
-
case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
+ gst_buffer_unref (sub);
break;
}
-
- if (avi->level_up) {
- avi->level_up--;
- break;
- }
}
+ /* we now have all info, letĀ“s set up a pad and a caps and be done */
/* create stream name + pad */
- switch (strh->type) {
+ switch (stream->strh->type) {
case GST_RIFF_FCC_vids:
- {
- char *codec_name = NULL;
- GstTagList *list = gst_tag_list_new ();
- guint32 tag;
-
padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
templ = gst_element_class_get_pad_template (klass, "video_%02d");
- if (strf.vids->compression)
- tag = strf.vids->compression;
- else
- tag = strh->fcc_handler;
- caps = gst_riff_create_video_caps_with_data (tag,
- strh, strf.vids, extradata, initdata, &codec_name);
- gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
- codec_name, NULL);
- gst_element_found_tags (GST_ELEMENT (avi), list);
- gst_tag_list_free (list);
- if (codec_name)
- g_free (codec_name);
- g_free (strf.vids);
+ caps = gst_riff_create_video_caps (stream->strf.vids->compression ?
+ stream->strf.vids->compression : stream->strh->fcc_handler,
+ stream->strh, stream->strf.vids,
+ stream->extradata, stream->initdata, &codec_name);
+ tag_name = GST_TAG_VIDEO_CODEC;
avi->num_v_streams++;
break;
- }
case GST_RIFF_FCC_auds:
- {
- char *codec_name = NULL;
- GstTagList *list = gst_tag_list_new ();
-
padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
templ = gst_element_class_get_pad_template (klass, "audio_%02d");
- caps =
- gst_riff_create_audio_caps_with_data (strf.auds->format, strh,
- strf.auds, extradata, initdata, &codec_name);
- gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
- codec_name, NULL);
- gst_element_found_tags (GST_ELEMENT (avi), list);
- gst_tag_list_free (list);
- if (codec_name)
- g_free (codec_name);
- blockalign = strf.auds->blockalign;
- bitrate = strf.auds->av_bps;
- g_free (strf.auds);
+ caps = gst_riff_create_audio_caps (stream->strf.auds->format,
+ stream->strh, stream->strf.auds,
+ stream->extradata, stream->initdata, &codec_name);
+ tag_name = GST_TAG_AUDIO_CODEC;
avi->num_a_streams++;
break;
- }
case GST_RIFF_FCC_iavs:
- {
- char *codec_name = NULL;
- GstTagList *list = gst_tag_list_new ();
-
padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
templ = gst_element_class_get_pad_template (klass, "video_%02d");
- caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs,
- &codec_name);
- gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
- codec_name, NULL);
- gst_element_found_tags (GST_ELEMENT (avi), list);
- gst_tag_list_free (list);
- if (codec_name)
- g_free (codec_name);
- g_free (strf.iavs);
+ caps = gst_riff_create_iavs_caps (stream->strh->fcc_handler,
+ stream->strh, stream->strf.iavs,
+ stream->extradata, stream->initdata, &codec_name);
+ tag_name = GST_TAG_VIDEO_CODEC;
avi->num_v_streams++;
break;
- }
default:
- g_assert (0);
+ g_assert_not_reached ();
+ }
+
+ /* no caps means no stream */
+ if (!caps) {
+ GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
+ goto fail;
}
/* set proper settings and add it */
- pad = gst_pad_new_from_template (templ, padname);
+ pad = stream->pad = gst_pad_new_from_template (templ, padname);
g_free (padname);
+ gst_pad_use_fixed_caps (pad);
gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
- gst_pad_set_getcaps_function (pad, gst_avi_demux_src_getcaps);
- stream = &avi->stream[avi->num_streams];
- stream->caps = caps ? caps : gst_caps_new_empty ();
- stream->pad = pad;
- stream->strh = strh;
stream->num = avi->num_streams;
- stream->delay = 0LL;
- stream->total_bytes = 0LL;
+ stream->total_bytes = 0;
stream->total_frames = 0;
stream->current_frame = 0;
stream->current_byte = 0;
stream->current_entry = -1;
- stream->skip = 0;
- stream->blockalign = blockalign;
- stream->bitrate = bitrate;
- stream->indexes = locations;
gst_pad_set_element_private (pad, stream);
avi->num_streams++;
-
- /* auto-negotiates */
+ gst_pad_set_active (pad, TRUE);
+ gst_pad_set_caps (pad, caps);
gst_element_add_pad (GST_ELEMENT (avi), pad);
-
- /* clean something up */
- if (initdata)
- gst_buffer_unref (initdata);
- if (extradata)
- gst_buffer_unref (extradata);
+ GST_LOG_OBJECT (element, "Added pad %s", gst_pad_get_name (pad));
return TRUE;
-skip_stream:
- while (TRUE) {
- if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
- return FALSE;
- if (avi->level_up) {
- avi->level_up--;
- break;
- }
- if (!gst_riff_read_skip (riff))
- return FALSE;
- }
-
- /* add a "NULL" stream */
+fail:
+ /* unref any mem that may be in use */
+ if (buf)
+ gst_buffer_unref (buf);
+ if (sub)
+ gst_buffer_unref (sub);
+ g_free (stream->strh);
+ g_free (stream->strf.data);
+ g_free (stream->name);
+ g_free (stream->indexes);
+ if (stream->initdata)
+ gst_buffer_unref (stream->initdata);
+ if (stream->extradata)
+ gst_buffer_unref (stream->extradata);
+ memset (stream, 0, sizeof (avi_stream_context));
avi->num_streams++;
- return TRUE; /* recoverable */
+ return FALSE;
}
-/*
- * Read an openDML-2.0 extension header.
+/**
+ * gst_avi_demux_parse_odml:
+ * @element: calling element (used for debug/error).
+ * @buf: input buffer to be used for parsing.
+ *
+ * Read an openDML-2.0 extension header. Fills in the frame number
+ * in the avi demuxer object when reading succeeds.
*/
-static gboolean
-gst_avi_demux_stream_odml (GstAviDemux * avi)
+static void
+gst_avi_demux_parse_odml (GstElement * element, GstBuffer * buf)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag;
-
- /* read contents */
- while (TRUE) {
- if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
- return FALSE;
- else if (avi->level_up) {
- avi->level_up--;
- break;
- }
+ GstAviDemux *avi = GST_AVI_DEMUX (element);
+ guint32 tag = 0;
+ guint offset = 4;
+ GstBuffer *sub = NULL;
+ while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
switch (tag) {
case GST_RIFF_TAG_dmlh:{
gst_riff_dmlh dmlh, *_dmlh;
- GstBuffer *buf;
- if (!gst_riff_read_data (riff, &tag, &buf))
- return FALSE;
- if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
- g_warning ("DMLH entry is too small (%d bytes, %d needed)",
+ if (GST_BUFFER_SIZE (sub) < sizeof (gst_riff_dmlh)) {
+ GST_ERROR_OBJECT (element,
+ "DMLH entry is too small (%d bytes, %d needed)",
GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_dmlh));
- gst_buffer_unref (buf);
+ gst_buffer_unref (sub);
break;
}
_dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
- GST_INFO ("dmlh tag found:");
- GST_INFO (" totalframes: %u", dmlh.totalframes);
+ GST_INFO_OBJECT (element, "dmlh tag found:");
+ GST_INFO_OBJECT (element, " totalframes: %u", dmlh.totalframes);
- avi->num_frames = dmlh.totalframes;
- gst_buffer_unref (buf);
+ avi->avih->tot_frames = dmlh.totalframes;
+ gst_buffer_unref (sub);
break;
}
default:
- GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
+ GST_WARNING_OBJECT (element,
+ "Unknown tag " GST_FOURCC_FORMAT " in ODML header",
GST_FOURCC_ARGS (tag));
/* fall-through */
-
case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
+ gst_buffer_unref (sub);
break;
}
-
- if (avi->level_up) {
- avi->level_up--;
- break;
- }
}
- return TRUE;
+ gst_buffer_unref (buf);
}
-/*
- * Seek to index, read it, seek back.
- * Return value indicates if we can continue processing. It
- * does not indicate if index-reading succeeded.
+/**
+ * gst_avi_demux_parse_index:
+ * @element: calling element (used for debugging/errors).
+ * @buf: buffer containing the full index.
+ * @entries_list: list (returned by this function) containing the index
+ * entries parsed from the buffer. The first in the list
+ * is also a pointer to the allocated data and should be
+ * free'ed at some point.
+ *
+ * Read index entries from the provided buffer.
*/
-static gboolean
-gst_avi_demux_stream_index (GstAviDemux * avi,
- GList ** index, GList ** alloc_list)
+static void
+gst_avi_demux_parse_index (GstElement * element,
+ GstBuffer * buf, GList ** _entries_list)
{
- GList *list = NULL;
- GstBuffer *buf = NULL;
- guint i;
- GstEvent *event;
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint64 pos_before, pos_after, length;
- guint32 tag;
- guint index_size;
- gst_avi_index_entry *index_entries = NULL;
-
- /* first, we need to know the current position (to seek back
- * when we're done) and the total length of the file. */
- length = gst_bytestream_length (riff->bs);
- pos_before = gst_bytestream_tell (riff->bs);
-
- /* skip movi
- *
- * FIXME:
- * - we want to add error handling here so we can recover.
- */
- if (!gst_riff_read_skip (riff))
- return FALSE;
-
- /* assure that we've got data left */
- pos_after = gst_bytestream_tell (riff->bs);
- if (pos_after + 8 > length) {
- g_warning ("File said that it has an index, but there is no index data!");
- goto end;
- }
+ GstAviDemux *avi = GST_AVI_DEMUX (element);
+ guint64 pos_before = avi->offset;
+ gst_avi_index_entry *entries = NULL;
+ guint8 *data;
+ GList *entries_list = NULL;
+ guint i, num, n;
- /* assure that it's an index */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_idx1) {
- g_warning ("No index after data, but " GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (tag));
- goto end;
+ if (!buf) {
+ *_entries_list = NULL;
+ return;
}
- /* read index */
- if (!gst_riff_read_data (riff, &tag, &buf))
- return FALSE;
-
- /* parse all entries */
- index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
- index_entries = g_malloc (index_size * sizeof (gst_avi_index_entry));
- GST_INFO ("%u index entries", avi->index_size);
+ data = GST_BUFFER_DATA (buf);
+ num = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
+ entries = g_new (gst_avi_index_entry, num);
- for (i = 0; i < index_size; i++) {
+ for (i = 0, n = 0; i < num; i++) {
gst_riff_index_entry entry, *_entry;
avi_stream_context *stream;
gint stream_nr;
gst_avi_index_entry *target;
GstFormat format;
- _entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
+ _entry = &((gst_riff_index_entry *) data)[i];
entry.id = GUINT32_FROM_LE (_entry->id);
entry.offset = GUINT32_FROM_LE (_entry->offset);
entry.flags = GUINT32_FROM_LE (_entry->flags);
entry.size = GUINT32_FROM_LE (_entry->size);
- target = &index_entries[i];
+ target = &entries[n];
- if (entry.id == GST_RIFF_rec || entry.id == 0)
+ if (entry.id == GST_RIFF_rec || entry.id == 0 ||
+ (entry.offset == 0 && n > 0))
continue;
stream_nr = CHUNKID_TO_STREAMNR (entry.id);
if (stream_nr >= avi->num_streams || stream_nr < 0) {
- GST_WARNING ("Index entry %d has invalid stream nr %d", i, stream_nr);
- target->stream_nr = -1;
+ GST_WARNING_OBJECT (element,
+ "Index entry %d has invalid stream nr %d", i, stream_nr);
continue;
}
target->stream_nr = stream_nr;
@@ -1262,7 +1201,7 @@ gst_avi_demux_stream_index (GstAviDemux * avi,
target->offset = entry.offset + 8;
/* figure out if the index is 0 based or relative to the MOVI start */
- if (i == 0) {
+ if (n == 0) {
if (target->offset < pos_before)
avi->index_offset = pos_before + 8;
else
@@ -1301,38 +1240,77 @@ gst_avi_demux_stream_index (GstAviDemux * avi,
target->index_nr, stream->total_frames - 1,
target->stream_nr, target->size, target->offset,
GST_TIME_ARGS (target->ts));
- list = g_list_prepend (list, target);
+ entries_list = g_list_prepend (entries_list, target);
+
+ n++;
+ }
+
+ *_entries_list = g_list_reverse (entries_list);
+ gst_buffer_unref (buf);
+}
+
+/**
+ * gst_avi_demux_stream_index:
+ * @avi: avi demuxer object.
+ * @index: list of index entries, returned by this function.
+ * @alloc_list: list of allocated data, returned by this function.
+ *
+ * Seeks to index and reads it.
+ */
+
+static void
+gst_avi_demux_stream_index (GstAviDemux * avi,
+ GList ** index, GList ** alloc_list)
+{
+ guint64 offset = avi->offset;
+ GstBuffer *buf;
+ guint32 tag;
+ gint i;
+
+ *alloc_list = NULL;
+ *index = NULL;
+
+ /* get position */
+ if (gst_pad_pull_range (avi->sinkpad, offset, 8, &buf) != GST_FLOW_OK)
+ return;
+ else if (!buf || GST_BUFFER_SIZE (buf) < 8) {
+ if (buf)
+ gst_buffer_unref (buf);
+ return;
}
+ offset += 8 + GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
+ gst_buffer_unref (buf);
+
+ /* get size */
+ if (gst_riff_read_chunk (GST_ELEMENT (avi),
+ avi->sinkpad, &offset, &tag, &buf) != GST_FLOW_OK)
+ return;
+ else if (tag != GST_RIFF_TAG_idx1) {
+ GST_ERROR_OBJECT (avi,
+ "No index data after movi chunk, but " GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (tag));
+ gst_buffer_unref (buf);
+ return;
+ }
+
+ gst_avi_demux_parse_index (GST_ELEMENT (avi), buf, index);
+ if (*index)
+ *alloc_list = g_list_append (*alloc_list, (*index)->data);
/* debug our indexes */
for (i = 0; i < avi->num_streams; i++) {
avi_stream_context *stream;
stream = &avi->stream[i];
- GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
+ GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
i, stream->total_frames, stream->total_bytes);
}
-end:
- if (buf)
- gst_buffer_unref (buf);
-
- /* seek back to the data */
- if (!(event = gst_riff_read_seek (riff, pos_before))) {
- g_free (index_entries);
- g_list_free (list);
- return FALSE;
- }
- gst_event_unref (event);
-
- if (list)
- *index = g_list_reverse (list);
- if (index_entries)
- *alloc_list = g_list_prepend (*alloc_list, index_entries);
-
- return TRUE;
+ return;
}
+#if 0
+
/*
* Sync to next data chunk.
*/
@@ -1572,6 +1550,10 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
stream->total_frames++;
list = g_list_prepend (list, entry);
+ GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %"
+ G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d",
+ index_size - 1, entry->frames_before, entry->offset,
+ GST_TIME_ARGS (entry->ts), entry->stream_nr);
next:
if (!gst_avi_demux_skip (avi, TRUE))
@@ -1591,6 +1573,7 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
return TRUE;
}
+#endif
/*
* Massage index.
@@ -1602,7 +1585,7 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
* order. The end result should be a smoother playing AVI.
*/
-static gint G_GNUC_UNUSED
+static gint
sort (gst_avi_index_entry * a, gst_avi_index_entry * b)
{
if (a->ts > b->ts)
@@ -1627,32 +1610,29 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
/* init frames */
for (i = 0; i < avi->num_streams; i++) {
GstFormat fmt = GST_FORMAT_TIME;
+ guint64 delay = 0;
stream = &avi->stream[i];
if (stream->strh->type == GST_RIFF_FCC_vids) {
if (!gst_pad_convert (stream->pad,
- GST_FORMAT_DEFAULT, stream->strh->init_frames,
- &fmt, &stream->delay)) {
- stream->delay = 0;
+ GST_FORMAT_DEFAULT, stream->strh->init_frames, &fmt, &delay)) {
+ delay = 0;
}
} else {
if (!gst_pad_convert (stream->pad,
- GST_FORMAT_DEFAULT, stream->strh->init_frames,
- &fmt, &stream->delay)) {
- stream->delay = 0;
+ GST_FORMAT_DEFAULT, stream->strh->init_frames, &fmt, &delay)) {
+ delay = 0;
}
}
GST_LOG ("Adding init_time=%" GST_TIME_FORMAT " to stream %d",
- GST_TIME_ARGS (stream->delay), i);
- }
- for (one = list; one != NULL; one = one->next) {
- entry = one->data;
+ GST_TIME_ARGS (delay), i);
- if (entry->stream_nr >= avi->num_streams)
- continue;
+ for (one = list; one != NULL; one = one->next) {
+ entry = one->data;
- stream = &avi->stream[entry->stream_nr];
- entry->ts += stream->delay;
+ if (entry->stream_nr == i)
+ entry->ts += delay;
+ }
}
GST_LOG ("I'm now going to cut large chunks into smaller pieces");
@@ -1674,7 +1654,7 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
* the allocation of index entries could be improved. */
stream = &avi->stream[entry->stream_nr];
if (entry->dur > MAX_DURATION && stream->strh->type == GST_RIFF_FCC_auds) {
- guint32 ideal_size = stream->bitrate / 10;
+ guint32 ideal_size = stream->strf.auds->av_bps / 10;
gst_avi_index_entry *entries;
gint old_size, num_added;
GList *one2;
@@ -1714,7 +1694,7 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
entry2->size = old_size;
}
- entry2->dur = GST_SECOND * entry2->size / stream->bitrate;
+ entry2->dur = GST_SECOND * entry2->size / stream->strf.auds->av_bps;
if (i != 0) {
entry2->index_nr++;
entry2->ts += entry->dur;
@@ -1760,141 +1740,149 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
* Read full AVI headers.
*/
-gboolean
+static GstFlowReturn
gst_avi_demux_stream_header (GstAviDemux * avi)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag, flags, streams;
+ GstFlowReturn res;
+ GstBuffer *buf, *sub = NULL;
+ guint32 tag;
GList *index = NULL, *alloc = NULL;
+ guint offset = 4;
/* the header consists of a 'hdrl' LIST tag */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_LIST) {
- GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
+ if ((res = gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad,
+ &avi->offset, &tag, &buf)) != GST_FLOW_OK)
+ return res;
+ else if (tag != GST_RIFF_TAG_LIST) {
+ GST_ELEMENT_ERROR (avi, STREAM, INVALID_DATA, (NULL),
("Invalid AVI header (no LIST at start): "
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
- return FALSE;
- }
- if (!gst_riff_read_list (riff, &tag))
- return FALSE;
- if (tag != GST_RIFF_LIST_hdrl) {
+ return GST_FLOW_ERROR;
+ } else if (GST_BUFFER_SIZE (buf) < 4 ||
+ GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl) {
GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
("Invalid AVI header (no hdrl at start): "
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
- return FALSE;
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
}
/* the hdrl starts with a 'avih' header */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_avih) {
+ if (!gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub) ||
+ tag != GST_RIFF_TAG_avih) {
GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
("Invalid AVI header (no avih at start): "
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
- return FALSE;
+ if (sub)
+ gst_buffer_unref (sub);
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
+ } else if (!gst_avi_demux_parse_avih (GST_ELEMENT (avi), sub, &avi->avih)) {
+ gst_buffer_unref (buf);
+ return GST_FLOW_ERROR;
}
- if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
- return FALSE;
/* now, read the elements from the header until the end */
- while (TRUE) {
- if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
- return FALSE;
- else if (avi->level_up) {
- avi->level_up--;
- break;
- }
-
+ while (gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub)) {
switch (tag) {
case GST_RIFF_TAG_LIST:
- if (!(tag = gst_riff_peek_list (riff)))
- return FALSE;
+ if (!sub || GST_BUFFER_SIZE (sub) < 4) {
+ if (sub)
+ gst_buffer_unref (sub);
+ break;
+ }
- switch (tag) {
+ switch (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))) {
case GST_RIFF_LIST_strl:
- if (!gst_riff_read_list (riff, &tag) ||
- !gst_avi_demux_add_stream (avi))
- return FALSE;
+ gst_avi_demux_parse_stream (GST_ELEMENT (avi), sub);
break;
-
case GST_RIFF_LIST_odml:
- if (!gst_riff_read_list (riff, &tag) ||
- !gst_avi_demux_stream_odml (avi))
- return FALSE;
+ gst_avi_demux_parse_odml (GST_ELEMENT (avi), sub);
break;
-
default:
- GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
- GST_FOURCC_ARGS (tag));
+ GST_WARNING_OBJECT (avi,
+ "Unknown list " GST_FOURCC_FORMAT " in AVI header",
+ GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))));
/* fall-through */
-
case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
+ gst_buffer_unref (sub);
break;
}
-
break;
-
default:
- GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
- GST_FOURCC_ARGS (tag));
+ GST_WARNING_OBJECT (avi,
+ "Unknown off %d tag " GST_FOURCC_FORMAT " in AVI header",
+ offset, GST_FOURCC_ARGS (tag));
/* fall-through */
-
case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
+ gst_buffer_unref (sub);
break;
}
-
- if (avi->level_up) {
- avi->level_up--;
- break;
- }
}
+ gst_buffer_unref (buf);
- if (avi->num_streams != streams) {
- g_warning ("Stream header mentioned %d streams, but %d available",
- streams, avi->num_streams);
+ /* check parsed streams */
+ if (avi->num_streams == 0) {
+ GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
+ return GST_FLOW_ERROR;
+ } else if (avi->num_streams != avi->avih->streams) {
+ GST_WARNING_OBJECT (avi,
+ "Stream header mentioned %d streams, but %d available",
+ avi->avih->streams, avi->num_streams);
}
/* Now, find the data (i.e. skip all junk between header and data) */
- while (1) {
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- if (tag != GST_RIFF_TAG_LIST) {
- if (!gst_riff_read_skip (riff))
- return FALSE;
- continue;
- }
- if (!(tag = gst_riff_peek_list (riff)))
- return FALSE;
- if (tag != GST_RIFF_LIST_movi) {
- if (tag == GST_RIFF_LIST_INFO) {
- if (!gst_riff_read_list (riff, &tag) || !gst_riff_read_info (riff))
- return FALSE;
- } else if (!gst_riff_read_skip (riff)) {
- return FALSE;
+ do {
+ guint size;
+ guint32 tag, ltag;
+
+ if ((res = gst_pad_pull_range (avi->sinkpad, avi->offset,
+ 12, &buf)) != GST_FLOW_OK)
+ return res;
+ else if (!buf || GST_BUFFER_SIZE (buf) < 12)
+ return GST_FLOW_ERROR;
+
+ tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
+ size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
+ ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8);
+ gst_buffer_unref (buf);
+
+ if (tag == GST_RIFF_TAG_LIST) {
+ switch (ltag) {
+ case GST_RIFF_LIST_movi:
+ goto done;
+ case GST_RIFF_LIST_INFO:
+ if ((res = gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad,
+ &avi->offset, &tag, &buf)) != GST_FLOW_OK)
+ return res;
+ else {
+ GstTagList *t;
+
+ sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4);
+ gst_riff_parse_info (GST_ELEMENT (avi), sub, &t);
+ if (t)
+ gst_tag_list_free (t);
+ gst_buffer_unref (buf);
+ }
+ default:
+ avi->offset += 8 + ((size + 1) & ~1);
+ break;
}
- continue;
+ } else {
+ avi->offset += 8 + ((size + 1) & ~1);
}
- break;
- }
+ } while (1);
+done:
/* create or read stream index (for seeking) */
if (avi->stream[0].indexes != NULL) {
- if (!gst_avi_demux_read_subindexes (avi, &index, &alloc))
- return FALSE;
+ gst_avi_demux_read_subindexes (avi, &index, &alloc);
}
if (!index) {
- if (flags & GST_RIFF_AVIH_HASINDEX) {
- if (!gst_avi_demux_stream_index (avi, &index, &alloc)) {
- g_list_foreach (alloc, (GFunc) g_free, NULL);
- g_list_free (alloc);
- return FALSE;
- }
+ if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) {
+ gst_avi_demux_stream_index (avi, &index, &alloc);
}
+#if 0
/* some indexes are incomplete, continue streaming from there */
if (!index || avi->stream[0].total_frames < avi->num_frames) {
if (!gst_avi_demux_stream_scan (avi, &index, &alloc)) {
@@ -1903,6 +1891,7 @@ gst_avi_demux_stream_header (GstAviDemux * avi)
return FALSE;
}
}
+#endif
}
if (index) {
gst_avi_demux_massage_index (avi, index, alloc);
@@ -1910,14 +1899,18 @@ gst_avi_demux_stream_header (GstAviDemux * avi)
g_list_free (index);
g_list_foreach (alloc, (GFunc) g_free, NULL);
g_list_free (alloc);
+
+ GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
+ ("Indexless reading todo"));
+ return GST_FLOW_ERROR;
}
/* at this point we know all the streams and we can signal the no more
* pads signal */
- GST_DEBUG ("signaling no more pads");
+ GST_DEBUG_OBJECT (avi, "signaling no more pads");
gst_element_no_more_pads (GST_ELEMENT (avi));
- return TRUE;
+ return GST_FLOW_OK;
}
/*
@@ -1933,116 +1926,115 @@ gst_avi_demux_handle_seek (GstAviDemux * avi)
/* FIXME: if we seek in an openDML file, we will have multiple
* primary levels. Seeking in between those will cause havoc. */
- avi->current_entry = avi->seek_entry;
+ GST_LOG ("Seeking to entry %d", avi->seek_entry);
for (i = 0; i < avi->num_streams; i++) {
avi_stream_context *stream = &avi->stream[i];
- if (GST_PAD_IS_USABLE (stream->pad)) {
- if (avi->seek_flush) {
- event = gst_event_new (GST_EVENT_FLUSH);
- gst_pad_push (stream->pad, GST_DATA (event));
- }
- event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
- avi->last_seek, NULL);
- gst_pad_push (stream->pad, GST_DATA (event));
- }
+ gst_pad_push_event (stream->pad, gst_event_new_flush (FALSE));
}
+ GST_STREAM_LOCK (avi->sinkpad);
+
+ avi->current_entry = avi->seek_entry;
+ for (i = 0; i < avi->num_streams; i++) {
+ avi_stream_context *stream = &avi->stream[i];
+
+ event = gst_event_new_discontinuous (1.0, GST_FORMAT_TIME, avi->last_seek,
+ (gint64) (((gfloat) stream->strh->scale) * stream->strh->length /
+ stream->strh->rate) * GST_SECOND, NULL);
+ gst_pad_push_event (stream->pad, gst_event_new_flush (TRUE));
+ gst_pad_push_event (stream->pad, event);
+ }
+ gst_task_start (GST_RPAD_TASK (avi->sinkpad));
+
+ GST_STREAM_UNLOCK (avi->sinkpad);
+
return TRUE;
}
-static gboolean
+static GstFlowReturn
gst_avi_demux_process_next_entry (GstAviDemux * avi)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- gboolean processed;
+ GstFlowReturn res;
+ gboolean processed = FALSE;
- for (processed = FALSE; !processed;) {
+ do {
if (avi->current_entry >= avi->index_size) {
- gst_bytestream_seek (riff->bs, 0, GST_SEEK_METHOD_END);
-
- /* get eos */
- gst_riff_peek_tag (GST_RIFF_READ (avi), &avi->level_up);
- gst_pad_event_default (avi->sinkpad, gst_event_new (GST_EVENT_EOS));
- processed = TRUE;
+ gint n;
+
+ GST_LOG_OBJECT (avi, "Handled last index entry, setting EOS (%d > %d)",
+ avi->current_entry, avi->index_size);
+ for (n = 0; n < avi->num_streams; n++) {
+ if (avi->stream[n].pad)
+ gst_pad_push_event (avi->stream[n].pad,
+ gst_event_new (GST_EVENT_EOS));
+ }
+ return GST_FLOW_WRONG_STATE;
} else {
GstBuffer *buf;
- guint got;
gst_avi_index_entry *entry = &avi->index_entries[avi->current_entry++];
avi_stream_context *stream;
if (entry->stream_nr >= avi->num_streams) {
+ GST_DEBUG_OBJECT (avi,
+ "Entry has non-existing stream nr %d", entry->stream_nr);
continue;
}
-
stream = &avi->stream[entry->stream_nr];
+ if (entry->size == 0 || !stream->pad) {
+ GST_DEBUG_OBJECT (avi, "Skipping entry %d (%d, %p)",
+ avi->current_entry - 1, entry->size, stream->pad);
+ goto next;
+ }
- if (GST_PAD_IS_USABLE (stream->pad) && entry->size > 0) {
- guint64 needed_off = entry->offset + avi->index_offset, pos;
- guint32 remain;
-
- pos = gst_bytestream_tell (riff->bs);
- gst_bytestream_get_status (riff->bs, &remain, NULL);
- if (pos <= needed_off && needed_off - pos <= remain) {
- gst_bytestream_flush_fast (riff->bs, needed_off - pos);
- } else {
- GstEvent *event;
-
- event = gst_riff_read_seek (riff, needed_off);
- if (event)
- gst_event_unref (event);
- else {
- GST_ELEMENT_ERROR (avi, RESOURCE, READ, (NULL), (NULL));
- return FALSE;
- }
- }
- if (!(buf = gst_riff_read_element_data (riff, entry->size, &got))) {
- return FALSE;
- }
- if (entry->flags & GST_RIFF_IF_KEYFRAME) {
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
- }
+ if ((res = gst_pad_pull_range (avi->sinkpad, entry->offset +
+ avi->index_offset, entry->size, &buf)) != GST_FLOW_OK)
+ return res;
+ else {
+ if (!(entry->flags & GST_RIFF_IF_KEYFRAME))
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DELTA_UNIT);
GST_BUFFER_TIMESTAMP (buf) = entry->ts;
GST_BUFFER_DURATION (buf) = entry->dur;
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
GST_DEBUG_OBJECT (avi, "Processing buffer of size %d and time %"
GST_TIME_FORMAT " on pad %s",
GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
gst_pad_get_name (stream->pad));
- gst_pad_push (stream->pad, GST_DATA (buf));
+ if ((res = gst_pad_push (stream->pad, buf)) != GST_FLOW_OK)
+ return res;
processed = TRUE;
}
+ next:
stream->current_frame = entry->frames_before + 1;
stream->current_byte = entry->bytes_before + entry->size;
}
- }
+ } while (!processed);
- return TRUE;
+ return GST_FLOW_OK;
}
/*
* Read data.
*/
-gboolean
+static GstFlowReturn
gst_avi_demux_stream_data (GstAviDemux * avi)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
- guint32 tag;
- guint stream_nr;
-
+#if 0
if (avi->seek_offset != (guint64) - 1) {
if (!gst_avi_demux_handle_seek (avi))
return FALSE;
avi->seek_offset = (guint64) - 1;
}
+#endif
/* if we have a avi->index_entries[], we don't want to read
* the stream linearly, but seek to the next ts/index_entry. */
- if (avi->index_entries != NULL) {
- return gst_avi_demux_process_next_entry (avi);
- }
-
+ //if (avi->index_entries != NULL) {
+ return gst_avi_demux_process_next_entry (avi);
+ //}
+#if 0
if (!gst_avi_demux_sync (avi, &tag, FALSE))
return FALSE;
stream_nr = CHUNKID_TO_STREAMNR (tag);
@@ -2089,7 +2081,8 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
GST_BUFFER_TIMESTAMP (buf) = next_ts;
gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &dur_ts);
GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
- GST_DEBUG ("Pushing buffer with time=%" GST_TIME_FORMAT " over pad %s",
+ GST_DEBUG_OBJECT (avi,
+ "Pushing buffer with time=%" GST_TIME_FORMAT " over pad %s",
GST_TIME_ARGS (next_ts), gst_pad_get_name (stream->pad));
gst_pad_push (stream->pad, GST_DATA (buf));
}
@@ -2097,34 +2090,85 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
}
return TRUE;
+#endif
}
static void
-gst_avi_demux_loop (GstElement * element)
+gst_avi_demux_loop (GstPad * pad)
{
- GstAviDemux *avi = GST_AVI_DEMUX (element);
+ GstFlowReturn res;
+ GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
+
+ GST_STREAM_LOCK (avi->sinkpad);
switch (avi->state) {
case GST_AVI_DEMUX_START:
- if (!gst_avi_demux_stream_init (avi))
- return;
+ if ((res = gst_avi_demux_stream_init (avi)) != GST_FLOW_OK)
+ goto pause;
avi->state = GST_AVI_DEMUX_HEADER;
/* fall-through */
-
case GST_AVI_DEMUX_HEADER:
- if (!gst_avi_demux_stream_header (avi))
- return;
+ if ((res = gst_avi_demux_stream_header (avi)) != GST_FLOW_OK)
+ goto pause;
avi->state = GST_AVI_DEMUX_MOVI;
break;
-
case GST_AVI_DEMUX_MOVI:
- if (!gst_avi_demux_stream_data (avi))
- return;
+ if ((res = gst_avi_demux_stream_data (avi)) != GST_FLOW_OK)
+ goto pause;
break;
+ default:
+ g_assert_not_reached ();
+ }
+ GST_STREAM_UNLOCK (avi->sinkpad);
+
+ return;
+
+pause:
+ GST_LOG_OBJECT (avi, "pausing task");
+ gst_task_pause (GST_RPAD_TASK (avi->sinkpad));
+ GST_STREAM_UNLOCK (pad);
+}
+
+static gboolean
+gst_avi_demux_sink_activate (GstPad * sinkpad, GstActivateMode mode)
+{
+ gboolean result = FALSE;
+ GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (sinkpad));;
+
+ switch (mode) {
+ case GST_ACTIVATE_PULL:
+ /* if we have a scheduler we can start the task */
+ if (GST_ELEMENT_SCHEDULER (avi)) {
+ GST_STREAM_LOCK (sinkpad);
+ GST_RPAD_TASK (sinkpad) =
+ gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (avi),
+ (GstTaskFunction) gst_avi_demux_loop, sinkpad);
+ gst_task_start (GST_RPAD_TASK (sinkpad));
+ GST_STREAM_UNLOCK (sinkpad);
+ result = TRUE;
+ }
+ break;
+ case GST_ACTIVATE_NONE:
+ /* step 1, unblock clock sync (if any) */
+
+ /* step 2, make sure streaming finishes */
+ GST_STREAM_LOCK (sinkpad);
+
+ /* step 3, stop the task */
+ if (GST_RPAD_TASK (sinkpad)) {
+ gst_task_stop (GST_RPAD_TASK (sinkpad));
+ gst_object_unref (GST_OBJECT (GST_RPAD_TASK (sinkpad)));
+ GST_RPAD_TASK (sinkpad) = NULL;
+ }
+ GST_STREAM_UNLOCK (sinkpad);
+ result = TRUE;
+ break;
default:
- g_assert (0);
+ break;
}
+
+ return result;
}
static GstElementStateReturn
diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h
index b506802ed..705f9057d 100644
--- a/gst/avi/gstavidemux.h
+++ b/gst/avi/gstavidemux.h
@@ -22,6 +22,7 @@
#include <gst/gst.h>
+#include "avi-ids.h"
#include "gst/riff/riff-ids.h"
#include "gst/riff/riff-read.h"
@@ -61,24 +62,25 @@ typedef struct {
/* pad, strh */
GstPad *pad;
- GstCaps *caps;
gst_riff_strh *strh;
- gint blockalign, bitrate;
+ union {
+ gst_riff_strf_vids *vids;
+ gst_riff_strf_auds *auds;
+ gst_riff_strf_iavs *iavs;
+ gpointer data;
+ } strf;
+ GstBuffer *extradata, *initdata;
+ gchar *name;
/* current position (byte, frame, time) */
guint current_frame;
guint64 current_byte;
gint current_entry;
- /* delay in time (init_frames) */
- guint64 delay;
-
/* stream length */
guint64 total_bytes;
guint32 total_frames;
- guint32 skip;
-
guint64 *indexes;
} avi_stream_context;
@@ -89,14 +91,14 @@ typedef enum {
} GstAviDemuxState;
typedef struct _GstAviDemux {
- GstRiffRead parent;
+ GstElement parent;
/* pads */
GstPad *sinkpad;
/* AVI decoding state */
GstAviDemuxState state;
- guint level_up;
+ guint64 offset;
/* index */
gst_avi_index_entry *index_entries;
@@ -111,8 +113,7 @@ typedef struct _GstAviDemux {
avi_stream_context stream[GST_AVI_DEMUX_MAX_STREAMS];
/* some stream info for length */
- guint32 us_per_frame;
- guint32 num_frames;
+ gst_riff_avih *avih;
/* seeking */
guint64 seek_offset;
@@ -122,7 +123,7 @@ typedef struct _GstAviDemux {
} GstAviDemux;
typedef struct _GstAviDemuxClass {
- GstRiffReadClass parent_class;
+ GstElementClass parent_class;
} GstAviDemuxClass;
GType gst_avi_demux_get_type (void);