Implemented riff parsing as a library. The avi parser can play simple PCM encoded audio.

Original commit message from CVS:
Implemented riff parsing as a library. The avi parser can play
simple PCM encoded audio.
some minor cleanups.
This commit is contained in:
Wim Taymans 2000-03-20 20:25:03 +00:00
parent 39d3ec0a0d
commit 1f4d20f689
16 changed files with 135 additions and 201 deletions

View file

@ -140,7 +140,11 @@ AC_CHECK_HEADER(xaudio/decoder.h,[
])
dnl Set location of plugin directory
if test "x${prefix}" = "xNONE"; then
PLUGINS_DIR=${ac_default_prefix}/lib/gst
else
PLUGINS_DIR=${prefix}/lib/gst
fi
AC_DEFINE_UNQUOTED(PLUGINS_DIR,"$PLUGINS_DIR")
AC_SUBST(PLUGINS_DIR)

View file

@ -187,12 +187,15 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
audiosink);
if (GST_BUFFER_DATA(buf) != NULL) {
gst_trace_add_entry(NULL,0,buf,"audiosink: writing to soundcard");
//g_print("audiosink: writing to soundcard\n");
if (audiosink->fd > 2)
write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
//g_print("audiosink: writing to soundcard ok\n");
}
//g_print("a unref\n");
gst_buffer_unref(buf);
// g_print("a");
//g_print("a done\n");
}
void gst_audiosink_set_format(GstAudioSink *audiosink,gint format) {

View file

@ -134,8 +134,10 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
/* we have to lock the queue since we span threads */
GST_LOCK(queue);
//g_print("queue: chain %d\n", queue->level_buffers);
if (queue->level_buffers >= queue->max_buffers) {
//g_print("queue: waiting %d\n", queue->level_buffers);
GST_UNLOCK(queue);
while (queue->level_buffers >= queue->max_buffers) {
g_mutex_lock(queue->fulllock);
@ -144,6 +146,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
g_mutex_unlock(queue->fulllock);
}
GST_LOCK(queue);
//g_print("queue: waiting done %d\n", queue->level_buffers);
}
@ -164,6 +167,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
tosignal = (queue->level_buffers++ == 0);
/* we can unlock now */
//g_print("queue: chain %d end\n", queue->level_buffers);
GST_UNLOCK(queue);
if (tosignal) {
@ -182,6 +186,7 @@ void gst_queue_push(GstConnection *connection) {
/* have to lock for thread-safety */
GST_LOCK(queue);
//g_print("queue: push %d\n", queue->level_buffers);
if (!queue->level_buffers) {
GST_UNLOCK(queue);
@ -197,12 +202,14 @@ void gst_queue_push(GstConnection *connection) {
front = queue->queue;
buf = (GstBuffer *)(front->data);
queue->queue = g_list_remove_link(queue->queue,front);
//g_print("queue: pushing %d\n", queue->level_buffers);
gst_pad_push(queue->srcpad,buf);
//g_print("queue: pushing %d done\n", queue->level_buffers);
g_list_free(front);
queue->level_buffers--;
//g_print("-");
tosignal = queue->level_buffers < queue->max_buffers;
//g_print("queue: push end %d\n", queue->level_buffers);
GST_UNLOCK(queue);
if (tosignal) {

View file

@ -71,13 +71,15 @@ static gboolean gst_plugin_load_recurse(gchar *directory,gchar *name) {
struct dirent *dirent;
gboolean loaded = FALSE;
//g_print("recursive load of '%s' in '%s'\n", name, directory);
dir = opendir(directory);
if (dir) {
while ((dirent = readdir(dir))) {
/* don't want to recurse in place or backwards */
if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
gst_plugin_load_recurse(g_strjoin("/",directory,dirent->d_name,
loaded = gst_plugin_load_recurse(g_strjoin("/",directory,dirent->d_name,
NULL),name);
if (loaded && name) return TRUE;
}
}
closedir(dir);
@ -87,13 +89,13 @@ static gboolean gst_plugin_load_recurse(gchar *directory,gchar *name) {
if (name) {
if ((temp = strstr(directory,name)) &&
(!strcmp(temp,name))) {
gst_plugin_load_absolute(directory);
return TRUE;
loaded = gst_plugin_load_absolute(directory);
return loaded;
}
} else if ((temp = strstr(directory,".so")) &&
(!strcmp(temp,".so"))) {
gst_plugin_load_absolute(directory);
loaded = TRUE;
loaded = gst_plugin_load_absolute(directory);
//return loaded;
}
}
}
@ -115,6 +117,19 @@ void gst_plugin_load_all() {
}
}
/**
* gst_library_load:
* @name: name of liabrary to load
*
* Load the named liabrary. Name should be given as
* &quot;libliabrary.so&quot;.
*
* Returns: whether the liabrary was loaded or not
*/
gboolean gst_library_load(gchar *name) {
// for now this is the same
return gst_plugin_load(name);
}
/**
* gst_plugin_load:
* @name: name of plugin to load
@ -142,7 +157,7 @@ gboolean gst_plugin_load(gchar *name) {
}
g_free(libspath);
//g_print("trying to load '%s' from '%s'\n",name,path->data);
if (gst_plugin_load_recurse(path->data,name)) {
if (gst_plugin_load_recurse(path->data,g_module_build_path("",name))) {
return TRUE;
}
path = g_list_next(path);
@ -161,14 +176,14 @@ gboolean gst_plugin_load_absolute(gchar *name) {
GstPluginInitFunc initfunc;
GstPlugin *plugin;
// g_print("trying to load '%s\n",name);
//g_print("trying to absolute load '%s\n",name);
if (g_module_supported() == FALSE) {
g_print("wow, you built this on a platform without dynamic loading???\n");
return FALSE;
}
module = g_module_open(name,0);
module = g_module_open(name,G_MODULE_BIND_LAZY);
if (module != NULL) {
if (g_module_symbol(module,"plugin_init",(gpointer *)&initfunc)) {
if ((plugin = (initfunc)(module))) {
@ -186,6 +201,7 @@ gboolean gst_plugin_load_absolute(gchar *name) {
return TRUE;
}
}
return TRUE;
} else if (_gst_plugin_spew) {
// if (strstr(g_module_error(),"No such") == NULL)
gst_info("error loading plugin: %s\n",g_module_error());

View file

@ -52,6 +52,7 @@ void gst_plugin_set_longname(GstPlugin *plugin,gchar *longname);
void _gst_plugin_initialize();
void gst_plugin_load_all();
gboolean gst_plugin_load(gchar *name);
gboolean gst_library_load(gchar *name);
gboolean gst_plugin_load_absolute(gchar *name);
void gst_plugin_add_factory(GstPlugin *plugin,GstElementFactory *factory);

View file

@ -1,139 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
/* list of paths to check for plugins */
GList *_plugin_paths;
/* whether or not to spew library load issues */
gboolean _plugin_spew = FALSE;
void plugin_initialize() {
_plugin_paths = NULL;
/* add the main (installed) library path */
_plugin_paths = g_list_prepend(_plugin_paths,PLUGINS_DIR);
/* if this is set, we add build-directory paths to the list */
#ifdef PLUGINS_USE_SRCDIR
_plugin_paths = g_list_prepend(_plugin_paths,PLUGINS_SRCDIR);
#endif /* PLUGINS_USE_SRCDIR */
}
static GModule *plugin_load_recurse(gchar *directory,gchar *name) {
DIR *dir;
struct dirent *dirent;
GModule *mod;
dir = opendir(directory);
if (dir) {
while (dirent = readdir(dir)) {
/* don't want to recurse in place or backwards */
if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
mod = plugin_load_recurse(g_strjoin("/",directory,dirent->d_name,
NULL),name);
if (mod != NULL) {
closedir(dir);
return mod;
}
}
}
closedir(dir);
} else {
if (strstr(directory,".so")) {
gchar *temp;
if (name) {
if ((temp = strstr(directory,name)) &&
(!strcmp(temp,name))) {
mod = plugin_load_absolute(directory);
if (mod != NULL) return mod;
}
} else if ((temp = strstr(directory,".so")) &&
(!strcmp(temp,".so"))) {
mod = plugin_load_absolute(directory);
if (mod != NULL) return mod;
}
}
}
return NULL;
}
/**
* plugin_load_all:
*
* Load all plugins in the path.
*/
void plugin_load_all() {
GList *path;
path = _plugin_paths;
while (path != NULL) {
plugin_load_recurse(path->data,NULL);
path = g_list_next(path);
}
}
/**
* plugin_load:
* @name: name of plugin to load
*
* Load the named plugin. Name should be given as
* &quot;libplugin.so&quot;.
*
* Returns: whether the plugin was loaded or not
*/
GModule *plugin_load(gchar *name) {
GList *path;
gchar *libspath;
GModule *mod;
// g_print("attempting to load plugin '%s'\n",name);
path = _plugin_paths;
while (path != NULL) {
mod = plugin_load_absolute(g_module_build_path(path->data,name));
if (mod != NULL) return mod;
libspath = g_strconcat(path->data,"/.libs",NULL);
// g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
mod = plugin_load_absolute(g_module_build_path(libspath,name));
if (mod != NULL) {
g_free(libspath);
return mod;
}
g_free(libspath);
// g_print("trying to load '%s' from '%s'\n",name,path->data);
mod = plugin_load_recurse(path->data,name);
if (mod != NULL) return mod;
path = g_list_next(path);
}
return NULL;
}
/**
* plugin_load_absolute:
* @name: name of plugin to load
*
* Returns: whether or not the plugin loaded
*/
GModule *plugin_load_absolute(gchar *name) {
GModule *mod;
// g_print("trying to load '%s\n",name);
if (g_module_supported() == FALSE) {
g_print("wow, you built this on a platform without dynamic loading???\n");
return;
}
mod = g_module_open(name,0);
if (mod != NULL) {
return mod;
} else if (_gst_plugin_spew) {
// if (strstr(g_module_error(),"No such") == NULL)
g_print("error loading plugin: %s\n",g_module_error());
}
return NULL;
}

View file

@ -1,4 +0,0 @@
void plugin_initialize();
void plugin_load_all();
GModule *plugin_load(gchar *name);
GModule *plugin_load_absolute(gchar *name);

View file

@ -34,26 +34,28 @@ GstRiff *gst_riff_new(GstRiffCallback function, gpointer data) {
riff->nextlikely = 0;
riff->new_tag_found = function;
riff->callback_data = data;
riff->incomplete_chunk = NULL;
return riff;
}
gint gst_riff_next_buffer(GstRiff *riff,GstBuffer *buf,gulong off) {
gulong last;
gulong last, size;
GstRiffChunk *chunk;
g_return_val_if_fail(riff != NULL, GST_RIFF_EINVAL);
g_return_val_if_fail(buf != NULL, GST_RIFF_EINVAL);
g_return_val_if_fail(GST_BUFFER_DATA(buf) != NULL, GST_RIFF_EINVAL);
last = off + GST_BUFFER_SIZE(buf);
size = GST_BUFFER_SIZE(buf);
last = off + size;
//g_print("offset new buffer 0x%08lx\n", off);
//g_print("offset new buffer 0x%08lx size 0x%08x\n", off, GST_BUFFER_SIZE(buf));
if (off == 0) {
gulong *words = (gulong *)GST_BUFFER_DATA(buf);
// don't even try to parse the head if it's not there
// don't even try to parse the head if it's not there FIXME
if (last < 12) {
riff->state = GST_RIFF_ENOTRIFF;
return riff->state;
@ -68,6 +70,32 @@ gint gst_riff_next_buffer(GstRiff *riff,GstBuffer *buf,gulong off) {
riff->form = words[2];
//g_print("form is 0x%08lx '%s'\n",words[2],gst_riff_id_to_fourcc(words[2]));
riff->nextlikely = 12; /* skip 'RIFF', length, and form */
// all OK here
riff->incomplete_chunk = NULL;
}
// if we have an incomplete chunk from the previous buffer
if (riff->incomplete_chunk) {
guint leftover;
//g_print("have incomplete chunk %08x filled\n", riff->incomplete_chunk_size);
leftover = riff->incomplete_chunk->size - riff->incomplete_chunk_size;
if (leftover <= size) {
//g_print("we can fill it from %08x with %08x bytes = %08x\n", riff->incomplete_chunk_size, leftover, riff->incomplete_chunk_size+leftover);
memcpy(riff->incomplete_chunk->data+riff->incomplete_chunk_size, GST_BUFFER_DATA(buf), leftover);
if (riff->new_tag_found) {
riff->new_tag_found(riff->incomplete_chunk, riff->callback_data);
}
g_free(riff->incomplete_chunk->data);
g_free(riff->incomplete_chunk);
riff->incomplete_chunk = NULL;
}
else {
//g_print("we cannot fill it %08x >= %08lx\n", leftover, size);
memcpy(riff->incomplete_chunk->data+riff->incomplete_chunk_size, GST_BUFFER_DATA(buf), size);
riff->incomplete_chunk_size += size;
return 0;
}
}
/* loop while the next likely chunk header is in this buffer */
@ -97,27 +125,44 @@ gint gst_riff_next_buffer(GstRiff *riff,GstBuffer *buf,gulong off) {
chunk->size = words[1];
chunk->data = (gchar *)(words+2);
// we need word alignment
if (chunk->size & 0x01) chunk->size++;
//if (chunk->size & 0x01) chunk->size++;
chunk->form = words[2]; /* fill in the form, might not be valid */
// send the buffer to the listener if we have received a function
if (riff->new_tag_found) {
riff->new_tag_found(chunk, riff->callback_data);
}
if (chunk->id == GST_RIFF_TAG_LIST) {
//g_print("found LIST %s\n", gst_riff_id_to_fourcc(chunk->form));
riff->nextlikely += 12;
// we push the list chunk on our 'stack'
riff->chunks = g_list_prepend(riff->chunks,chunk);
// send the buffer to the listener if we have received a function
if (riff->new_tag_found) {
riff->new_tag_found(chunk, riff->callback_data);
}
}
else {
//g_print("chunk id is 0x%08lx '%s' and is 0x%08lx long\n",words[0],
//g_print("chunk id offset %08x is 0x%08lx '%s' and is 0x%08lx long\n",riff->nextlikely, words[0],
// gst_riff_id_to_fourcc(words[0]),words[1]);
riff->nextlikely += 8 + chunk->size; /* doesn't include hdr */
// if this buffer is incomplete
if (riff->nextlikely > last) {
guint left = size - (riff->nextlikely - 0 - chunk->size - off);
//g_print("make incomplete buffer %08x\n", left);
chunk->data = g_malloc(chunk->size);
memcpy(chunk->data, (gchar *)(words+2), left);
riff->incomplete_chunk = chunk;
riff->incomplete_chunk_size = left;
}
else {
// send the buffer to the listener if we have received a function
if (riff->new_tag_found) {
riff->new_tag_found(chunk, riff->callback_data);
}
g_free(chunk);
}
//riff->chunks = g_list_prepend(riff->chunks,chunk);
}
}

View file

@ -286,6 +286,9 @@ struct _GstRiff {
/* list of chunks, most recent at the head */
GList *chunks;
/* incomplete chunks are assembled here */
GstRiffChunk *incomplete_chunk;
guint32 incomplete_chunk_size;
/* parse state */
gint state;
guint32 curoffset;

View file

@ -187,12 +187,15 @@ void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
audiosink);
if (GST_BUFFER_DATA(buf) != NULL) {
gst_trace_add_entry(NULL,0,buf,"audiosink: writing to soundcard");
//g_print("audiosink: writing to soundcard\n");
if (audiosink->fd > 2)
write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
//g_print("audiosink: writing to soundcard ok\n");
}
//g_print("a unref\n");
gst_buffer_unref(buf);
// g_print("a");
//g_print("a done\n");
}
void gst_audiosink_set_format(GstAudioSink *audiosink,gint format) {

View file

@ -134,8 +134,10 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
/* we have to lock the queue since we span threads */
GST_LOCK(queue);
//g_print("queue: chain %d\n", queue->level_buffers);
if (queue->level_buffers >= queue->max_buffers) {
//g_print("queue: waiting %d\n", queue->level_buffers);
GST_UNLOCK(queue);
while (queue->level_buffers >= queue->max_buffers) {
g_mutex_lock(queue->fulllock);
@ -144,6 +146,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
g_mutex_unlock(queue->fulllock);
}
GST_LOCK(queue);
//g_print("queue: waiting done %d\n", queue->level_buffers);
}
@ -164,6 +167,7 @@ void gst_queue_chain(GstPad *pad,GstBuffer *buf) {
tosignal = (queue->level_buffers++ == 0);
/* we can unlock now */
//g_print("queue: chain %d end\n", queue->level_buffers);
GST_UNLOCK(queue);
if (tosignal) {
@ -182,6 +186,7 @@ void gst_queue_push(GstConnection *connection) {
/* have to lock for thread-safety */
GST_LOCK(queue);
//g_print("queue: push %d\n", queue->level_buffers);
if (!queue->level_buffers) {
GST_UNLOCK(queue);
@ -197,12 +202,14 @@ void gst_queue_push(GstConnection *connection) {
front = queue->queue;
buf = (GstBuffer *)(front->data);
queue->queue = g_list_remove_link(queue->queue,front);
//g_print("queue: pushing %d\n", queue->level_buffers);
gst_pad_push(queue->srcpad,buf);
//g_print("queue: pushing %d done\n", queue->level_buffers);
g_list_free(front);
queue->level_buffers--;
//g_print("-");
tosignal = queue->level_buffers < queue->max_buffers;
//g_print("queue: push end %d\n", queue->level_buffers);
GST_UNLOCK(queue);
if (tosignal) {

View file

@ -23,26 +23,16 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
//if (0) {
if (strncmp(gst_pad_get_name(pad), "audio_", 6) == 0) {
// construct internal pipeline elements
parse_audio = gst_elementfactory_make("mp3parse","parse_audio");
g_return_if_fail(parse_audio != NULL);
decode = gst_elementfactory_make("mpg123","decode_audio");
g_return_if_fail(decode != NULL);
play = gst_elementfactory_make("audiosink","play_audio");
g_return_if_fail(play != NULL);
// create the thread and pack stuff into it
audio_thread = gst_thread_new("audio_thread");
g_return_if_fail(audio_thread != NULL);
gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(parse_audio));
gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(decode));
gst_bin_add(GST_BIN(audio_thread),GST_ELEMENT(play));
// set up pad connections
gst_element_add_ghost_pad(GST_ELEMENT(audio_thread),
gst_element_get_pad(parse_audio,"sink"));
gst_pad_connect(gst_element_get_pad(parse_audio,"src"),
gst_element_get_pad(decode,"sink"));
gst_pad_connect(gst_element_get_pad(decode,"src"),
gst_element_get_pad(play,"sink"));
// construct queue and connect everything in the main pipelie
@ -63,16 +53,13 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
} else if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
//} else if (0) {
gst_plugin_load("videosink");
// construct internal pipeline elements
parse_video = gst_elementfactory_make("mp1videoparse","parse_video");
g_return_if_fail(parse_video != NULL);
decode = gst_elementfactory_make("mpeg_play","decode_video");
g_return_if_fail(decode_video != NULL);
show = gst_elementfactory_make("videosink","show");
g_return_if_fail(show != NULL);
//gtk_object_set(GTK_OBJECT(show),"width",640, "height", 480,NULL);
appwindow = gnome_app_new("MPEG1 player","MPEG1 player");
appwindow = gnome_app_new("AVI player","AVI player");
gnome_app_set_contents(GNOME_APP(appwindow),
gst_util_get_widget_arg(GTK_OBJECT(show),"widget"));
gtk_widget_show_all(appwindow);
@ -80,16 +67,10 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
// create the thread and pack stuff into it
video_thread = gst_thread_new("video_thread");
g_return_if_fail(video_thread != NULL);
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(parse_video));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(decode));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(show));
// set up pad connections
gst_element_add_ghost_pad(GST_ELEMENT(video_thread),
gst_element_get_pad(parse_video,"sink"));
gst_pad_connect(gst_element_get_pad(parse_video,"src"),
gst_element_get_pad(decode,"sink"));
gst_pad_connect(gst_element_get_pad(decode,"src"),
gst_element_get_pad(show,"sink"));
// construct queue and connect everything in the main pipeline
@ -117,10 +98,11 @@ int main(int argc,char *argv[]) {
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
//_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gnome_init("AVI Video player","0.0.1",argc,argv);
gst_plugin_load_all();
//gst_plugin_load_all();
gst_plugin_load("parseavi");
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);

View file

@ -22,6 +22,8 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
// connect to audio pad
//if (0) {
if (strncmp(gst_pad_get_name(pad), "audio_", 6) == 0) {
gst_plugin_load("mp3parse");
gst_plugin_load("mpg123");
// construct internal pipeline elements
parse_audio = gst_elementfactory_make("mp3parse","parse_audio");
g_return_if_fail(parse_audio != NULL);
@ -63,6 +65,9 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
} else if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) {
//} else if (0) {
gst_plugin_load("mp1videoparse");
gst_plugin_load("mpeg_play");
gst_plugin_load("videosink");
// construct internal pipeline elements
parse_video = gst_elementfactory_make("mp1videoparse","parse_video");
g_return_if_fail(parse_video != NULL);
@ -117,10 +122,10 @@ int main(int argc,char *argv[]) {
g_print("have %d args\n",argc);
_gst_plugin_spew = TRUE;
//_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gnome_init("MPEG1 Video player","0.0.1",argc,argv);
gst_plugin_load_all();
gst_plugin_load("mpeg1parse");
pipeline = gst_pipeline_new("pipeline");
g_return_if_fail(pipeline != NULL);

View file

@ -19,9 +19,10 @@ int main(int argc,char *argv[]) {
GtkWidget *draw;
_gst_plugin_spew = TRUE;
//_gst_plugin_spew = TRUE;
gst_init(&argc,&argv);
gst_plugin_load_all();
gst_plugin_load("v4lsrc");
gst_plugin_load("videosink");
gnome_init("Videotest","0.0.1",argc,argv);