gst/wavparse/gstwavparse.*: reverted patch #337625 for the price of 1 hour sleep

Original commit message from CVS:
* gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
(gst_wavparse_class_init), (gst_wavparse_reset),
(gst_wavparse_init), (gst_wavparse_create_sourcepad),
(gst_wavparse_parse_file_header), (gst_wavparse_stream_init),
(gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
(gst_wavparse_send_event), (gst_wavparse_add_src_pad),
(gst_wavparse_stream_data), (gst_wavparse_loop),
(gst_wavparse_srcpad_event), (gst_wavparse_sink_activate),
(gst_wavparse_sink_activate_pull), (gst_wavparse_change_state),
(plugin_init):
* gst/wavparse/gstwavparse.h:
reverted patch #337625 for the price of 1 hour sleep
This commit is contained in:
Stefan Kost 2006-04-26 21:29:45 +00:00
parent 562de2f6e0
commit 422c6fcc0c
3 changed files with 173 additions and 450 deletions

View file

@ -1,3 +1,18 @@
2006-04-27 Stefan Kost <ensonic@users.sf.net>
* gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),
(gst_wavparse_class_init), (gst_wavparse_reset),
(gst_wavparse_init), (gst_wavparse_create_sourcepad),
(gst_wavparse_parse_file_header), (gst_wavparse_stream_init),
(gst_wavparse_perform_seek), (gst_wavparse_stream_headers),
(gst_wavparse_send_event), (gst_wavparse_add_src_pad),
(gst_wavparse_stream_data), (gst_wavparse_loop),
(gst_wavparse_srcpad_event), (gst_wavparse_sink_activate),
(gst_wavparse_sink_activate_pull), (gst_wavparse_change_state),
(plugin_init):
* gst/wavparse/gstwavparse.h:
reverted patch #337625 for the price of 1 hour sleep
2006-04-26 Stefan Kost <ensonic@users.sf.net> 2006-04-26 Stefan Kost <ensonic@users.sf.net>
* gst/wavparse/gstwavparse.c: (gst_wavparse_base_init), * gst/wavparse/gstwavparse.c: (gst_wavparse_base_init),

View file

@ -1,7 +1,6 @@
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
/* GStreamer /* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -32,18 +31,11 @@
* <title>Example launch line</title> * <title>Example launch line</title>
* <para> * <para>
* <programlisting> * <programlisting>
* gst-launch filesrc location=sine.wav ! queue ! wavparse ! audioconvert ! alsasink * gst-launch filesrc sine.wav ! wavparse ! audioconvert ! alsasink
* </programlisting> * </programlisting>
* Read a wav file and output to the soundcard using the ALSA element. The * Read a wav file and output to the soundcard using the ALSA element. The
* wav file is assumed to contain raw uncompressed samples. * wav file is assumed to contain raw uncompressed samples.
* </para> * </para>
* <para>
* <programlisting>
* gst-launch gnomevfssrc location=http://www.example.org/sine.wav ! wavparse ! audioconvert ! alsasink
* </programlisting>
* Stream data from
* </para>
*
* </refsect2> * </refsect2>
* *
* Last reviewed on 2006-03-03 (0.10.3) * Last reviewed on 2006-03-03 (0.10.3)
@ -59,24 +51,18 @@
#include "gst/riff/riff-media.h" #include "gst/riff/riff-media.h"
#include <gst/gst-i18n-plugin.h> #include <gst/gst-i18n-plugin.h>
#ifndef G_MAXUINT32
#define G_MAXUINT32 0xffffffff
#endif
GST_DEBUG_CATEGORY_STATIC (wavparse_debug); GST_DEBUG_CATEGORY_STATIC (wavparse_debug);
#define GST_CAT_DEFAULT (wavparse_debug) #define GST_CAT_DEFAULT (wavparse_debug)
static void gst_wavparse_base_init (gpointer g_class); static void gst_wavparse_base_init (gpointer g_class);
static void gst_wavparse_class_init (GstWavParseClass * klass); static void gst_wavparse_class_init (GstWavParseClass * klass);
static void gst_wavparse_init (GstWavParse * wavparse); static void gst_wavparse_init (GstWavParse * wavparse);
static void gst_wavparse_dispose (GObject * object);
static gboolean gst_wavparse_sink_activate (GstPad * sinkpad); static gboolean gst_wavparse_sink_activate (GstPad * sinkpad);
static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad, static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad,
gboolean active); gboolean active);
static gboolean gst_wavparse_send_event (GstElement * element, static gboolean gst_wavparse_send_event (GstElement * element,
GstEvent * event); GstEvent * event);
static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_wavparse_change_state (GstElement * element, static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
@ -91,12 +77,6 @@ static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
static void gst_wavparse_get_property (GObject * object, guint prop_id, static void gst_wavparse_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static const GstElementDetails gst_wavparse_details =
GST_ELEMENT_DETAILS ("WAV audio demuxer",
"Codec/Demuxer/Audio",
"Parse a .wav file into raw audio",
"Erik Walthinsen <omega@cse.ogi.edu>");
static GstStaticPadTemplate sink_template_factory = static GstStaticPadTemplate sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("wavparse_sink", GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
GST_PAD_SINK, GST_PAD_SINK,
@ -175,13 +155,22 @@ static void
gst_wavparse_base_init (gpointer g_class) gst_wavparse_base_init (gpointer g_class)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
GstPadTemplate *templ;
static GstElementDetails gst_wavparse_details =
GST_ELEMENT_DETAILS ("WAV audio demuxer",
"Codec/Demuxer/Audio",
"Parse a .wav file into raw audio",
"Erik Walthinsen <omega@cse.ogi.edu>");
gst_element_class_set_details (element_class, &gst_wavparse_details);
/* register src pads */ /* register src pads */
gst_element_class_add_pad_template (element_class, templ = gst_static_pad_template_get (&sink_template_factory);
gst_static_pad_template_get (&sink_template_factory)); gst_element_class_add_pad_template (element_class, templ);
gst_element_class_add_pad_template (element_class, gst_object_unref (templ);
gst_static_pad_template_get (&src_template_factory)); templ = gst_static_pad_template_get (&src_template_factory);
gst_element_class_set_details (element_class, &gst_wavparse_details); gst_element_class_add_pad_template (element_class, templ);
gst_object_unref (templ);
} }
static void static void
@ -196,28 +185,13 @@ gst_wavparse_class_init (GstWavParseClass * klass)
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
object_class->get_property = gst_wavparse_get_property; object_class->get_property = gst_wavparse_get_property;
object_class->dispose = gst_wavparse_dispose;
gstelement_class->change_state = gst_wavparse_change_state; gstelement_class->change_state = gst_wavparse_change_state;
gstelement_class->send_event = gst_wavparse_send_event; gstelement_class->send_event = gst_wavparse_send_event;
GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
} }
static void
gst_wavparse_dispose (GObject * object)
{
GST_DEBUG ("WAV: Dispose\n");
GstWavParse *wav = GST_WAVPARSE (object);
if (wav->adapter) {
g_object_unref (wav->adapter);
wav->adapter = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void static void
gst_wavparse_reset (GstWavParse * wavparse) gst_wavparse_reset (GstWavParse * wavparse)
{ {
@ -235,12 +209,6 @@ gst_wavparse_reset (GstWavParse * wavparse)
wavparse->dataleft = 0; wavparse->dataleft = 0;
wavparse->datasize = 0; wavparse->datasize = 0;
wavparse->datastart = 0; wavparse->datastart = 0;
wavparse->got_fmt = FALSE;
wavparse->first = TRUE;
if (wavparse->seek_event)
gst_event_unref (wavparse->seek_event);
wavparse->seek_event = NULL;
/* we keep the segment info in time */ /* we keep the segment info in time */
gst_segment_init (&wavparse->segment, GST_FORMAT_TIME); gst_segment_init (&wavparse->segment, GST_FORMAT_TIME);
@ -258,12 +226,7 @@ gst_wavparse_init (GstWavParse * wavparse)
GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate)); GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate));
gst_pad_set_activatepull_function (wavparse->sinkpad, gst_pad_set_activatepull_function (wavparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_pull)); GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_pull));
gst_pad_set_chain_function (wavparse->sinkpad,
GST_DEBUG_FUNCPTR (gst_wavparse_chain));
gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad); gst_element_add_pad (GST_ELEMENT (wavparse), wavparse->sinkpad);
/* src, will be created later */
wavparse->srcpad = NULL;
} }
static void static void
@ -291,8 +254,6 @@ gst_wavparse_create_sourcepad (GstWavParse * wavparse)
GST_DEBUG_FUNCPTR (gst_wavparse_pad_query)); GST_DEBUG_FUNCPTR (gst_wavparse_pad_query));
gst_pad_set_event_function (wavparse->srcpad, gst_pad_set_event_function (wavparse->srcpad,
GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event)); GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event));
GST_DEBUG_OBJECT (wavparse, "srcpad created");
} }
static void static void
@ -309,8 +270,6 @@ gst_wavparse_get_property (GObject * object,
} }
} }
#if 0 #if 0
static void static void
gst_wavparse_parse_adtl (GstWavParse * wavparse, int len) gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
@ -494,7 +453,9 @@ gst_wavparse_parse_adtl (GstWavParse * wavparse, int len)
g_object_notify (G_OBJECT (wavparse), "metadata"); g_object_notify (G_OBJECT (wavparse), "metadata");
} }
#endif
#if 0
static void static void
gst_wavparse_parse_cues (GstWavParse * wavparse, int len) gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
{ {
@ -557,7 +518,49 @@ gst_wavparse_parse_cues (GstWavParse * wavparse, int len)
g_object_notify (G_OBJECT (wavparse), "metadata"); g_object_notify (G_OBJECT (wavparse), "metadata");
} }
#endif
static gboolean
gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
{
guint32 doctype;
if (!gst_riff_parse_file_header (element, buf, &doctype))
return FALSE;
if (doctype != GST_RIFF_RIFF_WAVE)
goto not_wav;
return TRUE;
/* ERRORS */
not_wav:
{
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
("File is not an WAVE file: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (doctype)));
return FALSE;
}
}
static GstFlowReturn
gst_wavparse_stream_init (GstWavParse * wav)
{
GstFlowReturn res;
GstBuffer *buf = NULL;
if ((res = gst_pad_pull_range (wav->sinkpad,
wav->offset, 12, &buf)) != GST_FLOW_OK)
return res;
else if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), buf))
return GST_FLOW_ERROR;
wav->offset += 12;
return GST_FLOW_OK;
}
#if 0
/* Read 'fmt ' header */ /* Read 'fmt ' header */
static gboolean static gboolean
gst_wavparse_fmt (GstWavParse * wav) gst_wavparse_fmt (GstWavParse * wav)
@ -715,48 +718,6 @@ gst_wavparse_other (GstWavParse * wav)
} }
#endif #endif
static gboolean
gst_wavparse_parse_file_header (GstElement * element, GstBuffer * buf)
{
guint32 doctype;
if (!gst_riff_parse_file_header (element, buf, &doctype))
return FALSE;
if (doctype != GST_RIFF_RIFF_WAVE)
goto not_wav;
return TRUE;
/* ERRORS */
not_wav:
{
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
("File is not an WAVE file: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (doctype)));
return FALSE;
}
}
static GstFlowReturn
gst_wavparse_stream_init (GstWavParse * wav)
{
GstFlowReturn res;
GstBuffer *buf = NULL;
if ((res = gst_pad_pull_range (wav->sinkpad,
wav->offset, 12, &buf)) != GST_FLOW_OK)
return res;
else if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), buf))
return GST_FLOW_ERROR;
wav->offset += 12;
return GST_FLOW_OK;
}
/* This function is used to perform seeks on the element in /* This function is used to perform seeks on the element in
* pull mode. * pull mode.
* *
@ -779,6 +740,7 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
gboolean update; gboolean update;
GstSegment seeksegment; GstSegment seeksegment;
if (event) { if (event) {
GST_DEBUG_OBJECT (wav, "doing seek with event"); GST_DEBUG_OBJECT (wav, "doing seek with event");
@ -808,12 +770,10 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
flush = flags & GST_SEEK_FLAG_FLUSH; flush = flags & GST_SEEK_FLAG_FLUSH;
if (flush && wav->srcpad) { if (flush)
GST_DEBUG_OBJECT (wav, "sending flush start");
gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ()); gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ());
} else { else
gst_pad_pause_task (wav->sinkpad); gst_pad_pause_task (wav->sinkpad);
}
GST_PAD_STREAM_LOCK (wav->sinkpad); GST_PAD_STREAM_LOCK (wav->sinkpad);
@ -854,21 +814,18 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event)
GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop)); GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop));
/* prepare for streaming again */ /* prepare for streaming again */
if (wav->srcpad) { if (flush) {
if (flush) { gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ());
GST_DEBUG_OBJECT (wav, "sending flush stop"); } else if (wav->segment_running) {
gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ()); /* we are running the current segment and doing a non-flushing seek,
} else if (wav->segment_running) { * close the segment first based on the last_stop. */
/* we are running the current segment and doing a non-flushing seek, GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT
* close the segment first based on the last_stop. */ " to %" G_GINT64_FORMAT, wav->segment.start, wav->segment.last_stop);
GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT, wav->segment.start, wav->segment.last_stop);
gst_pad_push_event (wav->srcpad, gst_pad_push_event (wav->srcpad,
gst_event_new_new_segment (TRUE, gst_event_new_new_segment (TRUE,
wav->segment.rate, wav->segment.format, wav->segment.rate, wav->segment.format,
wav->segment.start, wav->segment.last_stop, wav->segment.time)); wav->segment.start, wav->segment.last_stop, wav->segment.time));
}
} }
memcpy (&wav->segment, &seeksegment, sizeof (GstSegment)); memcpy (&wav->segment, &seeksegment, sizeof (GstSegment));
@ -911,61 +868,6 @@ no_format:
} }
} }
/*
* gst_wavparse_peek_chunk_info:
* @wav Wavparse object
* @tag holder for tag
* @size holder for tag size
*
* Peek next chunk info (tag and size)
*
* Returns: %TRUE when one chunk info has been got from the adapter
*/
static gboolean
gst_wavparse_peek_chunk_info (GstWavParse * wav, guint32 * tag, guint32 * size)
{
const guint8 *data = NULL;
if (gst_adapter_available (wav->adapter) < 8) {
return FALSE;
}
GST_DEBUG ("Next chunk size is %d bytes", *size);
data = gst_adapter_peek (wav->adapter, 8);
*tag = GST_READ_UINT32_LE (data);
*size = GST_READ_UINT32_LE (data + 4);
return TRUE;
}
/*
* gst_wavparse_peek_chunk:
* @wav Wavparse object
* @tag holder for tag
* @size holder for tag size
*
* Peek enough data for one full chunk
*
* Returns: %TRUE when one chunk has been got
*/
static gboolean
gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size)
{
guint32 peek_size = 0;
gst_wavparse_peek_chunk_info (wav, tag, size);
GST_DEBUG ("Need to peek chunk of %d bytes", *size);
peek_size = (*size + 1) & ~1;
if (gst_adapter_available (wav->adapter) >= (8 + peek_size)) {
return TRUE;
} else {
return FALSE;
}
}
static gboolean static gboolean
gst_wavparse_get_upstream_size (GstWavParse * wav, gint64 * len) gst_wavparse_get_upstream_size (GstWavParse * wav, gint64 * len)
{ {
@ -985,127 +887,97 @@ static GstFlowReturn
gst_wavparse_stream_headers (GstWavParse * wav) gst_wavparse_stream_headers (GstWavParse * wav)
{ {
GstFlowReturn res; GstFlowReturn res;
GstBuffer *buf; GstBuffer *buf, *extra;
gst_riff_strf_auds *header = NULL; gst_riff_strf_auds *header = NULL;
guint32 tag, size; guint32 tag;
gboolean gotdata = FALSE; gboolean gotdata = FALSE;
GstCaps *caps; GstCaps *caps;
gint64 duration; gint64 duration;
gchar *codec_name = NULL; gchar *codec_name = NULL;
GstEvent **event_p; GstEvent **event_p;
if (!wav->got_fmt) { /* The header start with a 'fmt ' tag */
GstBuffer *extra; if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad,
&wav->offset, &tag, &buf)) != GST_FLOW_OK)
return res;
/* The header start with a 'fmt ' tag */ else if (tag != GST_RIFF_TAG_fmt)
goto invalid_wav;
if (wav->streaming) { if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra)))
if (!gst_wavparse_peek_chunk (wav, &tag, &size)) goto parse_header_error;
return GST_FLOW_OK;
buf = gst_buffer_new (); /* Note: gst_riff_create_audio_caps might nedd to fix values in
gst_buffer_ref (buf); * the header header depending on the format, so call it first */
gst_adapter_flush (wav->adapter, 8); caps =
wav->offset += 8; gst_riff_create_audio_caps (header->format, NULL, header, extra,
GST_BUFFER_DATA (buf) = (guint8 *) gst_adapter_peek (wav->adapter, size); NULL, &codec_name);
GST_BUFFER_SIZE (buf) = size;
} else { if (extra)
if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad, gst_buffer_unref (extra);
&wav->offset, &tag, &buf)) != GST_FLOW_OK)
return res;
}
if (tag != GST_RIFF_TAG_fmt) wav->format = header->format;
goto invalid_wav; wav->rate = header->rate;
wav->channels = header->channels;
if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra))) if (wav->channels == 0)
goto parse_header_error; goto no_channels;
if (extra) wav->blockalign = header->blockalign;
gst_buffer_unref (extra); wav->width = (header->blockalign * 8) / header->channels;
wav->depth = header->size;
wav->bps = header->av_bps;
if (wav->streaming) { if (wav->bps <= 0)
gst_adapter_flush (wav->adapter, size); goto no_bitrate;
wav->offset += size;
GST_BUFFER_DATA (buf) = NULL;
gst_buffer_unref (buf);
}
/* Note: gst_riff_create_audio_caps might nedd to fix values in wav->bytes_per_sample = wav->channels * wav->width / 8;
* the header header depending on the format, so call it first */ if (wav->bytes_per_sample <= 0)
caps = goto no_bytes_per_sample;
gst_riff_create_audio_caps (header->format, NULL, header, NULL,
NULL, &codec_name);
wav->format = header->format; g_free (header);
wav->rate = header->rate;
wav->channels = header->channels;
if (wav->channels == 0) if (!caps)
goto no_channels; goto unknown_format;
wav->blockalign = header->blockalign; GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign);
wav->width = (header->blockalign * 8) / header->channels; GST_DEBUG_OBJECT (wav, "width = %u", (guint) wav->width);
wav->depth = header->size; GST_DEBUG_OBJECT (wav, "depth = %u", (guint) wav->depth);
wav->bps = header->av_bps; GST_DEBUG_OBJECT (wav, "bps = %u", (guint) wav->bps);
if (wav->bps <= 0) /* create pad later so we can sniff the first few bytes
goto no_bitrate; * of the real data and correct our caps if necessary */
gst_caps_replace (&wav->caps, caps);
gst_caps_replace (&caps, NULL);
wav->bytes_per_sample = wav->channels * wav->width / 8; if (codec_name) {
if (wav->bytes_per_sample <= 0) wav->tags = gst_tag_list_new ();
goto no_bytes_per_sample;
g_free (header); gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
GST_TAG_AUDIO_CODEC, codec_name, NULL);
if (!caps) g_free (codec_name);
goto unknown_format; codec_name = NULL;
GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign);
GST_DEBUG_OBJECT (wav, "width = %u", (guint) wav->width);
GST_DEBUG_OBJECT (wav, "depth = %u", (guint) wav->depth);
GST_DEBUG_OBJECT (wav, "bps = %u", (guint) wav->bps);
/* create pad later so we can sniff the first few bytes
* of the real data and correct our caps if necessary */
gst_caps_replace (&wav->caps, caps);
gst_caps_replace (&caps, NULL);
wav->got_fmt = TRUE;
if (codec_name) {
wav->tags = gst_tag_list_new ();
gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE,
GST_TAG_AUDIO_CODEC, codec_name, NULL);
g_free (codec_name);
codec_name = NULL;
}
GST_DEBUG_OBJECT (wav, "frequency %d, channels %d", wav->rate,
wav->channels);
} }
GST_DEBUG_OBJECT (wav, "frequency %d, channels %d", wav->rate, wav->channels);
/* loop headers until we get data */ /* loop headers until we get data */
while (!gotdata) { while (!gotdata) {
if (wav->streaming) { guint size;
if (!gst_wavparse_peek_chunk_info (wav, &tag, &size)) guint32 tag;
return GST_FLOW_OK;
} else { if ((res =
if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, 8,
gst_pad_pull_range (wav->sinkpad, wav->offset, 8, &buf)) != GST_FLOW_OK)
&buf)) != GST_FLOW_OK) goto header_read_error;
goto header_read_error;
tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
}
/* /*
wav is a st00pid format, we don't know for sure where data starts. wav is a st00pid format, we don't know for sure where data starts.
So we have to go bit by bit until we find the 'data' header So we have to go bit by bit until we find the 'data' header
*/ */
tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
switch (tag) { switch (tag) {
/* TODO : Implement the various cases */ /* TODO : Implement the various cases */
@ -1114,11 +986,6 @@ gst_wavparse_stream_headers (GstWavParse * wav)
GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size); GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size);
gotdata = TRUE; gotdata = TRUE;
if (wav->streaming) {
gst_adapter_flush (wav->adapter, 8);
} else {
gst_buffer_unref (buf);
}
wav->offset += 8; wav->offset += 8;
wav->datastart = wav->offset; wav->datastart = wav->offset;
/* file might be truncated */ /* file might be truncated */
@ -1131,19 +998,12 @@ gst_wavparse_stream_headers (GstWavParse * wav)
break; break;
} }
default: default:
if (wav->streaming) {
if (!gst_wavparse_peek_chunk (wav, &tag, &size))
return GST_FLOW_OK;
}
GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT, GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (tag)); GST_FOURCC_ARGS (tag));
wav->offset += 8 + ((size + 1) & ~1); wav->offset += 8 + ((size + 1) & ~1);
if (wav->streaming) { break;
gst_adapter_flush (wav->adapter, 8 + ((size + 1) & ~1));
} else {
gst_buffer_unref (buf);
}
} }
gst_buffer_unref (buf);
} }
GST_DEBUG_OBJECT (wav, "Finished parsing headers"); GST_DEBUG_OBJECT (wav, "Finished parsing headers");
@ -1161,7 +1021,6 @@ gst_wavparse_stream_headers (GstWavParse * wav)
event_p = &wav->seek_event; event_p = &wav->seek_event;
gst_event_replace (event_p, NULL); gst_event_replace (event_p, NULL);
wav->state = GST_WAVPARSE_DATA;
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERROR */ /* ERROR */
@ -1221,32 +1080,6 @@ header_read_error:
} }
} }
/*
* Read WAV file tag when streaming
*/
static GstFlowReturn
gst_wavparse_parse_stream_init (GstWavParse * wav)
{
if (gst_adapter_available (wav->adapter) >= 12) {
GstBuffer *tmp = gst_buffer_new ();
/* _take flushes the data */
GST_BUFFER_DATA (tmp) = gst_adapter_take (wav->adapter, 12);
GST_BUFFER_SIZE (tmp) = 12;
GST_DEBUG ("Parsing wav header");
if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), tmp)) {
return GST_FLOW_ERROR;
}
wav->offset += 12;
/* Go to next state */
wav->state = GST_WAVPARSE_HEADER;
}
return GST_FLOW_OK;
}
/* handle an event sent directly to the element. /* handle an event sent directly to the element.
* *
* This event can be sent either in the READY state or the * This event can be sent either in the READY state or the
@ -1267,8 +1100,6 @@ gst_wavparse_send_event (GstElement * element, GstEvent * event)
gboolean res = FALSE; gboolean res = FALSE;
GstEvent **event_p; GstEvent **event_p;
GST_DEBUG_OBJECT (wav, "received event %s", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
if (wav->state == GST_WAVPARSE_DATA) { if (wav->state == GST_WAVPARSE_DATA) {
@ -1318,7 +1149,6 @@ gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad);
gst_element_no_more_pads (GST_ELEMENT (wav)); gst_element_no_more_pads (GST_ELEMENT (wav));
GST_DEBUG_OBJECT (wav, "Send newsegment event on newpad");
gst_pad_push_event (wav->srcpad, wav->newsegment); gst_pad_push_event (wav->srcpad, wav->newsegment);
wav->newsegment = NULL; wav->newsegment = NULL;
@ -1331,7 +1161,7 @@ gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
#define MAX_BUFFER_SIZE 4096 #define MAX_BUFFER_SIZE 4096
static GstFlowReturn static GstFlowReturn
gst_wavparse_stream_data (GstWavParse * wav) gst_wavparse_stream_data (GstWavParse * wav, gboolean first)
{ {
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res = GST_FLOW_OK;
@ -1339,10 +1169,8 @@ gst_wavparse_stream_data (GstWavParse * wav)
GstClockTime timestamp, next_timestamp; GstClockTime timestamp, next_timestamp;
guint64 pos, nextpos; guint64 pos, nextpos;
iterate_adapter: GST_LOG_OBJECT (wav, "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT,
GST_LOG_OBJECT (wav, wav->offset, wav->end_offset);
"offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft);
/* Get the next n bytes and output them */ /* Get the next n bytes and output them */
if (wav->dataleft == 0 || wav->dataleft < wav->blockalign) if (wav->dataleft == 0 || wav->dataleft < wav->blockalign)
@ -1359,32 +1187,18 @@ iterate_adapter:
GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data " GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data "
"from the sinkpad", desired); "from the sinkpad", desired);
if (wav->streaming) { if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
guint avail = gst_adapter_available (wav->adapter); desired, &buf)) != GST_FLOW_OK)
goto pull_error;
if (avail < desired) { obtained = GST_BUFFER_SIZE (buf);
GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail);
return GST_FLOW_OK;
}
buf = gst_buffer_new ();
GST_BUFFER_DATA (buf) = gst_adapter_take (wav->adapter, desired);
GST_BUFFER_SIZE (buf) = desired;
} else {
if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset,
desired, &buf)) != GST_FLOW_OK)
goto pull_error;
}
/* first chunk of data? create the source pad. We do this only here so /* first chunk of data? create the source pad. We do this only here so
* we can detect broken .wav files with dts disguised as raw PCM (sigh) */ * we can detect broken .wav files with dts disguised as raw PCM (sigh) */
if (G_UNLIKELY (wav->first)) { if (first) {
wav->first = FALSE;
gst_wavparse_add_src_pad (wav, buf); gst_wavparse_add_src_pad (wav, buf);
} }
obtained = GST_BUFFER_SIZE (buf);
/* our positions */ /* our positions */
pos = wav->offset - wav->datastart; pos = wav->offset - wav->datastart;
nextpos = pos + obtained; nextpos = pos + obtained;
@ -1411,29 +1225,15 @@ iterate_adapter:
", size:%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), ", size:%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf)); GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf));
if (gst_pad_is_linked (wav->srcpad)) { if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK)
if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK) goto push_error;
goto push_error;
} else {
gst_buffer_unref (buf);
goto not_linked;
}
if (obtained < wav->dataleft) { if (obtained < wav->dataleft) {
wav->dataleft -= obtained; wav->dataleft -= obtained;
//wav->offset += obtained; wav->offset += obtained;
} else { } else {
wav->dataleft = 0; wav->dataleft = 0;
} }
wav->offset += obtained;
/* Iterate until need more data, so adapter size won't grow */
if (wav->streaming) {
GST_LOG_OBJECT (wav,
"offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset,
wav->end_offset);
goto iterate_adapter;
}
return res; return res;
/* ERROR */ /* ERROR */
@ -1467,11 +1267,6 @@ push_error:
GST_DEBUG_OBJECT (wav, "Error pushing on srcpad"); GST_DEBUG_OBJECT (wav, "Error pushing on srcpad");
return res; return res;
} }
not_linked:
{
GST_DEBUG_OBJECT (wav, "Srcpad not linked!");
return GST_FLOW_ERROR;
}
} }
static void static void
@ -1480,11 +1275,8 @@ gst_wavparse_loop (GstPad * pad)
GstFlowReturn ret; GstFlowReturn ret;
GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (wav, "process data");
switch (wav->state) { switch (wav->state) {
case GST_WAVPARSE_START: case GST_WAVPARSE_START:
GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START");
if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK) if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK)
goto pause; goto pause;
@ -1492,15 +1284,15 @@ gst_wavparse_loop (GstPad * pad)
/* fall-through */ /* fall-through */
case GST_WAVPARSE_HEADER: case GST_WAVPARSE_HEADER:
GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER");
if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
goto pause; goto pause;
wav->state = GST_WAVPARSE_DATA; wav->state = GST_WAVPARSE_DATA;
/* fall-through */ if ((ret = gst_wavparse_stream_data (wav, TRUE)) != GST_FLOW_OK)
goto pause;
break;
case GST_WAVPARSE_DATA: case GST_WAVPARSE_DATA:
if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) if ((ret = gst_wavparse_stream_data (wav, FALSE)) != GST_FLOW_OK)
goto pause; goto pause;
break; break;
default: default:
@ -1523,58 +1315,6 @@ pause:
} }
} }
static GstFlowReturn
gst_wavparse_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret;
GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (wav, "adapter_push %" G_GINT64_FORMAT " bytes",
GST_BUFFER_SIZE (buf));
gst_adapter_push (wav->adapter, buf);
switch (wav->state) {
case GST_WAVPARSE_START:
GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START");
if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK)
goto pause;
wav->state = GST_WAVPARSE_HEADER;
/* fall-through */
case GST_WAVPARSE_HEADER:
GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER");
if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK)
goto pause;
wav->state = GST_WAVPARSE_DATA;
/* fall-through */
case GST_WAVPARSE_DATA:
if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK)
goto pause;
break;
default:
g_assert_not_reached ();
}
return ret;
pause:
GST_LOG_OBJECT (wav, "pausing task %d", ret);
gst_pad_pause_task (wav->sinkpad);
if (GST_FLOW_IS_FATAL (ret)) {
/* for fatal errors we post an error message */
GST_ELEMENT_ERROR (wav, STREAM, FAILED,
(_("Internal data stream error.")),
("streaming stopped, reason %s", gst_flow_get_name (ret)));
if (wav->srcpad != NULL)
gst_pad_push_event (wav->srcpad, gst_event_new_eos ());
}
return ret;
}
#if 0 #if 0
/* convert and query stuff */ /* convert and query stuff */
static const GstFormat * static const GstFormat *
@ -1786,8 +1526,7 @@ gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad));
gboolean res = TRUE; gboolean res = TRUE;
GST_DEBUG_OBJECT (wavparse, "event %d, %s", GST_EVENT_TYPE (event), GST_DEBUG_OBJECT (wavparse, "event %d", GST_EVENT_TYPE (event));
GST_EVENT_TYPE_NAME (event));
/* can only handle events when we are in the data state */ /* can only handle events when we are in the data state */
if (wavparse->state != GST_WAVPARSE_DATA) if (wavparse->state != GST_WAVPARSE_DATA)
@ -1812,34 +1551,20 @@ gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event)
static gboolean static gboolean
gst_wavparse_sink_activate (GstPad * sinkpad) gst_wavparse_sink_activate (GstPad * sinkpad)
{ {
GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad)); if (gst_pad_check_pull_range (sinkpad))
if (gst_pad_check_pull_range (sinkpad)) {
GST_DEBUG ("going to pull mode");
wav->streaming = FALSE;
wav->adapter = NULL;
gst_object_unref (wav);
return gst_pad_activate_pull (sinkpad, TRUE); return gst_pad_activate_pull (sinkpad, TRUE);
} else {
GST_DEBUG ("going to push (streaming) mode");
wav->streaming = TRUE;
wav->adapter = gst_adapter_new ();
gst_object_unref (wav);
return gst_pad_activate_push (sinkpad, TRUE);
}
}
/* FIXME, we can only operate in pull mode for now */
GST_DEBUG_OBJECT (sinkpad, "pull_range not supported on sinkpad");
return FALSE;
};
static gboolean static gboolean
gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active) gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active)
{ {
GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad)); GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad));
GST_DEBUG_OBJECT (wav, "activating pull");
if (active) { if (active) {
/* if we have a scheduler we can start the task */
wav->segment_running = TRUE;
gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad); gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad);
} else { } else {
gst_pad_stop_task (sinkpad); gst_pad_stop_task (sinkpad);
@ -1855,8 +1580,6 @@ gst_wavparse_change_state (GstElement * element, GstStateChange transition)
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstWavParse *wav = GST_WAVPARSE (element); GstWavParse *wav = GST_WAVPARSE (element);
GST_DEBUG_OBJECT (wav, "chaning state");
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_NULL_TO_READY:
break; break;
@ -1880,11 +1603,8 @@ gst_wavparse_change_state (GstElement * element, GstStateChange transition)
gst_wavparse_destroy_sourcepad (wav); gst_wavparse_destroy_sourcepad (wav);
gst_event_replace (event_p, NULL); gst_event_replace (event_p, NULL);
gst_wavparse_reset (wav); gst_wavparse_reset (wav);
if (wav->adapter) {
gst_adapter_clear (wav->adapter);
}
break;
} }
break;
case GST_STATE_CHANGE_READY_TO_NULL: case GST_STATE_CHANGE_READY_TO_NULL:
break; break;
default: default:
@ -1898,8 +1618,6 @@ plugin_init (GstPlugin * plugin)
{ {
gst_riff_init (); gst_riff_init ();
GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser");
return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY, return gst_element_register (plugin, "wavparse", GST_RANK_PRIMARY,
GST_TYPE_WAVPARSE); GST_TYPE_WAVPARSE);
} }

View file

@ -1,6 +1,5 @@
/* GStreamer /* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -26,7 +25,6 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gst/riff/riff-ids.h" #include "gst/riff/riff-ids.h"
#include "gst/riff/riff-read.h" #include "gst/riff/riff-read.h"
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -95,17 +93,9 @@ struct _GstWavParse {
/* pending seek */ /* pending seek */
GstEvent *seek_event; GstEvent *seek_event;
/* For streaming */
GstAdapter *adapter;
gboolean got_fmt;
gboolean streaming;
/* configured segment, start/stop expressed in time */ /* configured segment, start/stop expressed in time */
GstSegment segment; GstSegment segment;
gboolean segment_running; gboolean segment_running;
/* for late pad configuration */
gboolean first;
}; };
struct _GstWavParseClass { struct _GstWavParseClass {