[mistelix] Get rid of MistelixLib and introduce Backend.GStreamer. Better separation of libmistelix
- From: Jordi Mas <jmas src gnome org>
- To: svn-commits-list gnome org
- Subject: [mistelix] Get rid of MistelixLib and introduce Backend.GStreamer. Better separation of libmistelix
- Date: Sun, 26 Jul 2009 13:26:11 +0000 (UTC)
commit e49e13ffd1d1c886a20bd0a2ac492c9a90400561
Author: Jordi Mas <jmas softcatala org>
Date: Sun Jul 26 15:25:44 2009 +0200
Get rid of MistelixLib and introduce Backend.GStreamer. Better separation of libmistelix
libmistelix/Makefile.am | 5 +-
libmistelix/mistelix.c | 670 +---------------------------------
libmistelix/mistelix.h | 26 +-
libmistelix/plugins.c | 111 ++++++
libmistelix/slideshow.c | 551 ++++++++++++++++++++++++++++
libmistelix/typefind.c | 92 +++++
libmistelix/video.c | 109 +++---
po/POTFILES.in | 2 +-
src/Backends/GStreamer/Plugins.cs | 69 ++++
src/Backends/GStreamer/SlideShow.cs | 125 +++++++
src/Backends/GStreamer/Thumbnail.cs | 58 +++
src/Backends/GStreamer/Video.cs | 123 +++++++
src/Backends/OS/Unix.cs | 93 +++++
src/Core/Dependencies.cs | 3 +-
src/Core/DvdProjectBuilder.cs | 5 +-
src/Core/MistelixLib.cs | 260 -------------
src/Core/Preferences.cs | 45 +---
src/Core/SlideShow.cs | 14 +-
src/Core/Video.cs | 5 +-
src/DataModel/VideoProjectElement.cs | 5 +-
src/Makefile.am | 8 +-
src/Widgets/VideosFileView.cs | 6 +-
22 files changed, 1330 insertions(+), 1055 deletions(-)
---
diff --git a/libmistelix/Makefile.am b/libmistelix/Makefile.am
index 628e5c9..2dae415 100644
--- a/libmistelix/Makefile.am
+++ b/libmistelix/Makefile.am
@@ -10,7 +10,10 @@ dolib_LTLIBRARIES = libmistelix.la
libmistelix_la_SOURCES = \
mistelix.c \
thumbnail.c \
- video.c
+ video.c \
+ slideshow.c \
+ plugins.c \
+ typefind.c
noinst_HEADERS = \
mistelix.h
diff --git a/libmistelix/mistelix.c b/libmistelix/mistelix.c
index 7190efc..6b9a2cd 100644
--- a/libmistelix/mistelix.c
+++ b/libmistelix/mistelix.c
@@ -21,217 +21,21 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#include <stdio.h>
-#include <netdb.h>
#include <unistd.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <gst/gst.h>
#include <sys/wait.h>
#include "mistelix.h"
+static gboolean gstreamer_init = 0;
-typedef struct
-{
- gchar filename [1024];
- unsigned int weight;
- unsigned int height;
- unsigned int frames_sec;
- unsigned int total_frames;
- unsigned int type;
-} ThreadParams;
-
-typedef enum
-{
- None = 0,
- InitParams = 1, /* Length (4 bytes) + pixels */
- NewImage = 2, /* Length (4 bytes) seconds */
- FixedImage = 3, /* Length (4 bytes) + nframes + pixels */
- End = 4
-} Command;
-
-
-const gchar* address = "localhost";
-const int port = 2048;
-static int mis_socket;
-ThreadParams params;
-char audio[1024];
-int started;
-GThread* thread;
-gboolean gstreamer_init = 0;
-
-// It is assumed that there is only one client using the library at the time
-// There are no handles for session, just the active session
-
-void
-mistelix_slideshow_createstream (const gchar* filename, unsigned int type, unsigned int weight, unsigned int height, unsigned int frames_sec, unsigned int total_frames)
-{
-#ifdef _DEBUG
- printf ("*** mistelix_slideshow_createstream: %s, %u, %u, %u, %u\n", filename, type, weight, height, frames_sec);
-#endif
- thread = NULL;
- started = 0;
- *audio = '\x0';
- strcpy ((char*) params.filename,filename);
- params.weight = weight;
- params.height = height;
- params.frames_sec = frames_sec;
- params.total_frames = total_frames;
- params.type = type;
-}
-
-void
-mistelix_slideshow_add_image (unsigned char* bytes, unsigned int len)
-{
- unsigned char header[6];
- unsigned char* pos = (unsigned char*) &len;
- int i;
-#ifdef _DEBUG
- printf ("*** mistelix_slideshow_add_image %x\n", len);
-#endif
- mistelix_check_started ();
-
- // Command
- header[0] = 0xff;
- header[1] = NewImage;
-
- // Len
- for (i = 0; i < sizeof (unsigned int); i++) {
- header[2 + i] = *pos;
- pos++;
- }
-
- mistelix_socket_send (header, 6);
- mistelix_socket_send (bytes, len);
-}
-
-void
-mistelix_slideshow_add_imagefixed (unsigned char* bytes, unsigned int len, unsigned int frames)
-{
- unsigned char header[10]; // 2 bytes header, 4 length buffer, 4 number of frames
- unsigned char* pos = (unsigned char*) &len;
- int i;
-#ifdef _DEBUG
- printf ("*** mistelix_slideshow_add_image_fixed %x %u\n", len, frames);
-#endif
- mistelix_check_started ();
-
- // Command
- header[0] = 0xff;
- header[1] = FixedImage;
-
- // Len
- for (i = 0; i < sizeof (unsigned int); i++) {
- header[2 + i] = *pos;
- pos++;
- }
-
- // Frames
- pos = (unsigned char*) &frames;
- for (i = 0; i < sizeof (unsigned int); i++) {
- header[6 + i] = *pos;
- pos++;
- }
-
- mistelix_socket_send (header, 10);
- mistelix_socket_send (bytes, len);
-}
-
-
-void
-mistelix_slideshow_close ()
-{
- // Wait until the pipe line completes
- g_thread_join (thread);
-}
-
-
-void
-mistelix_slideshow_add_audio (const gchar* filename)
-{
- strcpy (audio, filename);
-}
-
-unsigned int
-mistelix_get_codecs_count ()
-{
- GList *plugins, *plugins_org, *features;
- GstPluginFeature *feature;
- GstPlugin *plugin;
- unsigned int count = 0;
- gboolean was_init;
-
- was_init = gstreamer_init;
- mistelix_check_init ();
-
-#ifdef _GSTREAMER_BUG
- /* This code can be enabled when gst-ffmpeg bug fix http://bugzilla.gnome.org/show_bug.cgi?id=584291
- becomes widely available */
-
- if (was_init)
- gst_update_registry (); /* Detect new plugins added since we started GStreamer */
-#endif
-
- plugins_org = plugins = gst_default_registry_get_plugin_list ();
-
- while (plugins) {
- plugin = (GstPlugin *) (plugins->data);
- count++;
- features = gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), plugin->desc.name);
- while (features) {
- feature = GST_PLUGIN_FEATURE (features->data);
- if (GST_IS_ELEMENT_FACTORY (feature))
- count++;
-
- features = g_list_next (features);
- }
- gst_plugin_list_free (features);
- plugins = g_list_next (plugins);
- }
- gst_plugin_list_free (plugins_org);
- return count;
-}
-
-// TODO: These are not really codec are plug-ins
void
-mistelix_get_codecs (char *codecs[])
+mistelix_check_init ()
{
- GList *plugins, *features;
- GstPlugin *plugin;
- GstPluginFeature *feature;
- const char *name;
- int cnt = 0;
-
- mistelix_check_init ();
- plugins = gst_default_registry_get_plugin_list ();
-
- while (plugins) {
- plugin = (GstPlugin *) (plugins->data);
- codecs[cnt] = malloc (strlen (plugin->desc.name) + 1);
- strcpy (codecs[cnt], plugin->desc.name);
- cnt++;
-
- features = gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), plugin->desc.name);
-
- while (features) {
- feature = GST_PLUGIN_FEATURE (features->data);
- name = gst_plugin_feature_get_name (feature);
-
- if (GST_IS_ELEMENT_FACTORY (feature)) {
- codecs[cnt] = malloc (strlen (name) + 1);
- strcpy (codecs[cnt], name);
- cnt++;
- }
+ if (gstreamer_init == TRUE)
+ return;
- features = g_list_next (features);
- }
- gst_plugin_list_free (features);
- plugins = g_list_next (plugins);
- }
- gst_plugin_list_free (plugins);
+ gst_init (NULL, NULL);
+ gstreamer_init = TRUE;
}
//
@@ -305,465 +109,3 @@ void mistelix_launchtool (const char* app, const char* args, const char* in_file
execvp (app, parmList);
}
-void
-mistelix_check_init ()
-{
- if (gstreamer_init == TRUE)
- return;
-
- gst_init (NULL, NULL);
- gstreamer_init = TRUE;
-}
-
-/*
- Do not want to start the thread until is necessary
- to allow for example to add an audio channel before launching it
-*/
-void
-mistelix_check_started ()
-{
- if (started != 0)
- return;
-
- started = 1;
-
- thread = g_thread_create (mistelix_launch_gstreamer, (gpointer) ¶ms, TRUE, NULL);
- // TODO: To be replaced by socket timeout
- sleep (2);
- mistelix_socket_connect ();
-}
-
-/*
- Sends a seek event to a pad
-*/
-void
-send_seek_event (GstElement* pipeline, GstPad* pad, gboolean flush)
-{
- gboolean res = FALSE;
- GstEvent *event;
- GstSeekFlags flags;
-
- flags = GST_SEEK_FLAG_SEGMENT;
-
- if (flush)
- flags |= GST_SEEK_FLAG_FLUSH;
-
- /* Seek from the begining */
- event = gst_event_new_seek (1, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
- res = gst_pad_send_event (pad, event);
- if (res)
- gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
- else
- printf ("send_seek_event: error sending seek event\n");
-}
-
-/*
- Monitor the EOS event for the sink pad
- and resend it to the pipeline to finish it
-*/
-static gboolean
-gst_handle_sink_event (GstPad * pad, GstEvent * event)
-{
- GstElement* element = (GstElement *) gst_object_get_parent (GST_OBJECT (pad));
-
-#ifdef _DEBUG
- printf ("--->* gst_handle_sink_event %s %s -> %s (%u)\n",
- gst_element_get_name (element),
- gst_element_get_name (pad),
- gst_event_type_get_name (event->type),
- event->type);
-#endif
- if (event->type == GST_EVENT_EOS) {
- GstElement* pipe = (GstElement *) gst_object_get_parent (GST_OBJECT (element));
- GstBus *bus = gst_element_get_bus (pipe);
- gst_bus_post (bus, gst_message_new_eos (GST_OBJECT (pipe)));
-#ifdef _DEBUG
- printf ("Posted EOS\n");
-#endif
- }
- return gst_pad_event_default (pad, event);
-}
-
-#ifdef _DEBUG
-
-/*
- Lists all the elements in a pipeline
-*/
-void
-listelements (GstBin* bin)
-{
- gpointer point, point_pad;
- GstIterator *it, *it_pads;
-
- it = gst_bin_iterate_elements (bin);
-
- printf ("----\n");
- while (gst_iterator_next (it, &point) == GST_ITERATOR_OK) {
- GstElement* element = GST_ELEMENT (point);
-
- it_pads = gst_element_iterate_pads (element);
- printf ("element -> %s\n", gst_element_get_name (element));
-
- while (gst_iterator_next (it_pads, &point_pad) == GST_ITERATOR_OK) {
- GstPad * pad = GST_PAD (point_pad);
- printf ("pad-> %s\n", gst_element_get_name (pad));
- }
- }
- printf ("----\n");
-}
-#endif
-
-gboolean
-mistelix_is_codec (const char* name)
-{
- int ncodecs, i;
- gboolean found = FALSE;
-
- ncodecs = mistelix_get_codecs_count ();
-
- char *codecs[ncodecs];
- mistelix_get_codecs (codecs);
-
- for (i = 0; i < ncodecs; i++ )
- {
- if (strcmp (name, codecs[i]) == 0) {
- found = TRUE;
- break;
- }
- }
-
- for (i = 0; i < ncodecs; i++)
- free (codecs [i]);
-
-#ifdef _DEBUG
- printf ("Codec %s, found %d\n", name, found);
-#endif
- return found;
-}
-
-/*
- Get the element name within the pipeline
- Caller is responsible for freezing the allocated memory
-*/
-char *
-mistelix_get_element_name_from_pipeline (GstBin* pipe, char* generic_name)
-{
- char* result = NULL;
- gpointer point;
- GstIterator* it;
- int len;
-
- len = strlen (generic_name);
- it = gst_bin_iterate_elements (pipe);
-
- while (gst_iterator_next (it, &point) == GST_ITERATOR_OK) {
- GstElement* element = GST_ELEMENT (point);
- char* name;
-
- name = gst_element_get_name (element);
-
- if (strncmp (name, generic_name, len) == 0) {
- result = malloc (strlen (name) + 1);
- strcpy (result, name);
- break;
- }
- }
-#ifdef _DEBUG
- printf ("Seached %s, found %s\n", generic_name, result);
-#endif
- return result;
-}
-
-/* Method to launch gstreamer thread. Method signature as required by g_thread_create */
-gpointer
-mistelix_launch_gstreamer (gpointer data)
-{
- char desc [1024];
- GstElement* pipe, *element;
- ThreadParams* params = (ThreadParams *) data;
- gboolean has_audio;
- GstBus *bus;
- GstMessage *message;
- GstStateChangeReturn ret;
- GstPad* seekable_pad;
- gpointer point_pad;
- GstIterator *it_pads;
- char* element_name;
- int sink = 0;
- gboolean vorbis;
- char media [2048];
-
- mistelix_check_init ();
-
- has_audio = (*audio != '\x0');
-
- if (has_audio) {
- mistelix_detect_media (audio, media);
-
- if (strcmp (media, "application/ogg") == 0) {
- if (mistelix_is_codec ("vorbisdec"))
- vorbis = TRUE;
- else
- has_audio = FALSE;
- } else {
- if (strcmp (media, "application/x-id3") == 0) {
- if (mistelix_is_codec ("flump3dec"))
- vorbis = FALSE;
- else
- has_audio = FALSE;
- } else {
- printf ("mistelix: unsupported audio format: %s\n", media);
- has_audio = FALSE;
- }
- }
- }
-
- if (params->type == 0) {/* Theora output format */
- if (has_audio) {
- if (vorbis) { /* Source audio in Vorbis */
- sprintf (desc,
- "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
- "theoraenc ! mux. filesrc location=\"%s\" ! oggdemux ! vorbisdec ! audioconvert ! vorbisenc ! "
- "oggmux name=mux ! filesink location=\"%s\"",
- params->total_frames, params->weight, params->height, params->frames_sec, audio, params->filename);
- } else { /* Source audio in MP3 */
- sprintf (desc,
- "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
- "theoraenc ! mux. filesrc location=\"%s\" ! flump3dec ! audioconvert ! vorbisenc ! "
- "oggmux name=mux ! filesink location=\"%s\"",
- params->total_frames, params->weight, params->height, params->frames_sec, audio, params->filename);
- }
- } else {
- sprintf (desc,
- "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
- "theoraenc ! oggmux !filesink location=\"%s\"",
- params->total_frames, params->weight, params->height, params->frames_sec, params->filename);
- }
- }
- else { /* DVD output format */
-
- /*
- * ffenc_mpeg2video
- * We use 'bitrate'element to set the quality of the generated MPEG2 video.
- * Every additional 10000 bits/s represent approximately 10% additional time
- * to generate the video
- *
- * ffmux_dvd
- * We use maxdelay and preload to generate MPEG2 compatible streams with DVD
- */
-
- /* No audio support for now */
- sprintf (desc,
- "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
- "ffenc_mpeg2video bitrate=500000 ! ffmux_dvd preload=500000 maxdelay=699999 !filesink location=\"%s\"",
- params->total_frames, params->weight, params->height, params->frames_sec, params->filename);
- }
-#ifdef _DEBUG
- printf ("mistelix_launch_gstreamer: %s\n", desc);
-#endif
- pipe = gst_parse_launch (desc, NULL);
-
- /* Launch pipeline */
-
-#ifdef _DEBUG
- listelements (GST_BIN (pipe));
- printf ("*** run_pipeline start\n");
-#endif
-
- g_assert (pipe);
- bus = gst_element_get_bus (pipe);
- g_assert (bus);
-
- gst_element_set_state (pipe, GST_STATE_PLAYING);
-
- /* Wait for status change */
- gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
-
- if (has_audio) {
-
- /* Find the pad of the audio decoder to send the audio seek events */
- if (vorbis)
- element_name = mistelix_get_element_name_from_pipeline (GST_BIN (pipe), "vorbisdec");
- else
- element_name = mistelix_get_element_name_from_pipeline (GST_BIN (pipe), "flump3dec");
-
- g_assert (element_name);
- element = gst_bin_get_by_name (GST_BIN (pipe), element_name);
- free (element_name);
-
- g_assert (element);
- seekable_pad = gst_element_get_pad (element, "src");
- g_assert (seekable_pad);
-
- /* Find the muxer's sink's and set callback function */
- element = gst_bin_get_by_name (GST_BIN (pipe), "mux");
- g_assert (element);
-
- it_pads = gst_element_iterate_pads (element);
- while (gst_iterator_next (it_pads, &point_pad) == GST_ITERATOR_OK) {
- GstPad * pad = GST_PAD (point_pad);
-
- if (strncmp (gst_element_get_name (pad), "src", 3) == 0)
- continue;
-
- sink++;
- if (sink < 2)
- continue;
-
- /* The second sink is the video sink */
- #ifdef _DEBUG
- printf ("Setting handler for %s\n", gst_element_get_name (pad));
- #endif
- gst_pad_set_event_function (pad, gst_handle_sink_event);
- break;
- }
-
- send_seek_event (pipe, seekable_pad, FALSE);
- }
- /* We get a GST_MESSAGE_EOS when the pipe is finished */
- while (1) {
- GstMessageType revent;
-
- message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
-
- if (message) {
- revent = GST_MESSAGE_TYPE (message);
-#ifdef _DEBUG
- printf ("*** run_pipeline message: %s (%x)\n", gst_message_type_get_name (revent), revent);
-#endif
- gst_message_unref (message);
- } else
- revent = GST_MESSAGE_UNKNOWN;
-
- if (revent == GST_MESSAGE_SEGMENT_DONE) {
- /* Send audio segment again */
- send_seek_event (pipe, seekable_pad, TRUE);
- continue;
- }
-
- if (revent == GST_MESSAGE_ERROR) {
-#ifdef _DEBUG
- printf ("*** run_pipeline exiting reason GST_MESSAGE_ERROR\n");
-#endif
- break;
- }
-
- if (revent == GST_MESSAGE_EOS) {
-#ifdef _DEBUG
- printf ("*** run_pipeline exiting reason: GST_MESSAGE_EOS\n");
-#endif
- break;
- }
- }
-
- /* Need to explicitly set elements to the NULL state before dropping the final reference */
- gst_element_set_state (pipe, GST_STATE_NULL);
- gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
- gst_object_unref (pipe);
- gst_object_unref (bus);
-
-#ifdef _DEBUG
- printf ("*** run_pipeline end\n");
-#endif
- return NULL;
-}
-
-void
-mistelix_socket_connect ()
-{
- struct sockaddr_in serveraddr;
- int yes = 1;
-#ifdef _DEBUG
- printf ("*** mistelix_socket_connect %s %u\n", address, port);
-#endif
- if ((mis_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
- return;
-
- if (setsockopt (mis_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
- {
- close (mis_socket);
- return;
- }
-
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_addr.s_addr = INADDR_ANY;
- serveraddr.sin_port = htons (port);
- memset (&(serveraddr.sin_zero), '\0', 8);
-
- if (connect (mis_socket,(struct sockaddr *)&serveraddr,sizeof (serveraddr)) < 0)
- {
- printf ("*** mistelix_socket_connect error. It may be caused because not all the assumed pipe elements are present\n");
- return;
- }
-
- printf ("*** mistelix_socket_connect %d\n", mis_socket);
-}
-
-void
-mistelix_socket_send (unsigned char* data, unsigned int bytes)
-{
- write (mis_socket, data, bytes);
-}
-
-
-/*
- Runs standard pipline that ends by an EOS event
-*/
-void
-run_pipeline (GstElement * pipe)
-{
- GstBus *bus;
- GstMessage *message;
- GstMessageType revent;
- GstStateChangeReturn ret;
-
-#ifdef _DEBUG
- printf ("*** run_pipeline start\n");
-#endif
- g_assert (pipe);
- bus = gst_element_get_bus (pipe);
- g_assert (bus);
-
- gst_element_set_state (pipe, GST_STATE_PLAYING);
-
- /* Wait for status change */
- gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
-
- /* We get a GST_MESSAGE_EOS when the pipe is finished */
- while (1) {
- message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
-
- if (message) {
- revent = GST_MESSAGE_TYPE (message);
-#ifdef _DEBUG
- printf ("*** run_pipeline message: %s (%x)\n", gst_message_type_get_name (revent), revent);
-#endif
- gst_message_unref (message);
- } else
- revent = GST_MESSAGE_UNKNOWN;
-
- if (revent == GST_MESSAGE_ERROR) {
-#ifdef _DEBUG
- printf ("*** run_pipeline exiting reason GST_MESSAGE_ERROR\n");
-#endif
- break;
- }
-
- if (revent == GST_MESSAGE_EOS) {
-#ifdef _DEBUG
- printf ("*** run_pipeline exiting reason: GST_MESSAGE_EOS\n");
-#endif
- break;
- }
- }
-
- gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
- //gst_object_unref (pipe);
-
- gst_bus_set_flushing (bus, TRUE);
- //gst_object_unref (bus);
-#ifdef _DEBUG
- printf ("*** run_pipeline end\n");
-#endif
-}
-
diff --git a/libmistelix/mistelix.h b/libmistelix/mistelix.h
index f952439..7397296 100644
--- a/libmistelix/mistelix.h
+++ b/libmistelix/mistelix.h
@@ -34,6 +34,7 @@
#include <gst/check/gstcheck.h>
/* Public API */
+
void mistelix_slideshow_createstream (const gchar* filename, unsigned int type, unsigned int weight, unsigned int height, unsigned int framessec, unsigned int total_frames);
void mistelix_slideshow_add_image (unsigned char* bytes, unsigned int len);
@@ -46,34 +47,23 @@ void mistelix_slideshow_close ();
void mistelix_launchtool (const char* app, const char* args, const char* in, const char* out, const char* err);
-int mistelix_convert_media (const char* filein, const char* fileout, unsigned int frames_sec);
-
-void mistelix_video_screenshot (const char* filein, void** image);
-
-unsigned int mistelix_get_codecs_count ();
+int mistelix_video_convert (const char* filein, const char* fileout, unsigned int frames_sec);
-void mistelix_get_codecs (char *codecs[]);
+int mistelix_video_supported (const char* file, char* msg);
+void mistelix_video_screenshot (const char* filein, void** image);
-/* Private (not exposed) */
+unsigned int mistelix_get_plugins_count ();
-char * mistelix_get_element_name_from_pipeline (GstBin* pipe, char* generic_name);
+void mistelix_get_plugins (char *plugins[]);
-void mistelix_detect_media (const char* file, char* media);
-
-static void cb_typefound (GstElement *typefind, guint probability, GstCaps *caps, gpointer data);
+/* Private (not exposed) but shared within the library */
void mistelix_check_init ();
void mistelix_check_started ();
-void run_pipeline (GstElement * pipe);
-
-gpointer mistelix_launch_gstreamer (gpointer data);
-
-void mistelix_socket_connect ();
-
-void mistelix_socket_send (unsigned char *data, unsigned int bytes);
+void mistelix_detect_media (const char* file, char* media);
diff --git a/libmistelix/plugins.c b/libmistelix/plugins.c
new file mode 100644
index 0000000..005c845
--- /dev/null
+++ b/libmistelix/plugins.c
@@ -0,0 +1,111 @@
+//
+// Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "mistelix.h"
+
+extern gboolean gstreamer_init;
+
+unsigned int
+mistelix_get_plugins_count ()
+{
+ GList *plugins, *plugins_org, *features;
+ GstPluginFeature *feature;
+ GstPlugin *plugin;
+ unsigned int count = 0;
+ gboolean was_init;
+
+ was_init = gstreamer_init;
+ mistelix_check_init ();
+
+#ifdef _GSTREAMER_BUG
+ /* This code can be enabled when gst-ffmpeg bug fix http://bugzilla.gnome.org/show_bug.cgi?id=584291
+ becomes widely available */
+
+ if (was_init)
+ gst_update_registry (); /* Detect new plugins added since we started GStreamer */
+#endif
+
+ plugins_org = plugins = gst_default_registry_get_plugin_list ();
+
+ while (plugins) {
+ plugin = (GstPlugin *) (plugins->data);
+ count++;
+ features = gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), plugin->desc.name);
+ while (features) {
+ feature = GST_PLUGIN_FEATURE (features->data);
+ if (GST_IS_ELEMENT_FACTORY (feature))
+ count++;
+
+ features = g_list_next (features);
+ }
+ gst_plugin_list_free (features);
+ plugins = g_list_next (plugins);
+ }
+ gst_plugin_list_free (plugins_org);
+ return count;
+}
+
+// TODO: These are not really codec are plug-ins
+void
+mistelix_get_plugins (char *plugins[])
+{
+ GList *plugins_list, *features;
+ GstPlugin *plugin;
+ GstPluginFeature *feature;
+ const char *name;
+ int cnt = 0;
+
+ mistelix_check_init ();
+ plugins_list = gst_default_registry_get_plugin_list ();
+
+ while (plugins_list) {
+ plugin = (GstPlugin *) (plugins_list->data);
+ plugins[cnt] = malloc (strlen (plugin->desc.name) + 1);
+ strcpy (plugins[cnt], plugin->desc.name);
+ cnt++;
+
+ features = gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), plugin->desc.name);
+
+ while (features) {
+ feature = GST_PLUGIN_FEATURE (features->data);
+ name = gst_plugin_feature_get_name (feature);
+
+ if (GST_IS_ELEMENT_FACTORY (feature)) {
+ plugins[cnt] = malloc (strlen (name) + 1);
+ strcpy (plugins[cnt], name);
+ cnt++;
+ }
+
+ features = g_list_next (features);
+ }
+ gst_plugin_list_free (features);
+ plugins_list = g_list_next (plugins_list);
+ }
+ gst_plugin_list_free (plugins_list);
+}
+
+
diff --git a/libmistelix/slideshow.c b/libmistelix/slideshow.c
new file mode 100644
index 0000000..c11a33f
--- /dev/null
+++ b/libmistelix/slideshow.c
@@ -0,0 +1,551 @@
+//
+// Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+
+#include "mistelix.h"
+
+
+typedef struct
+{
+ gchar filename [1024];
+ unsigned int weight;
+ unsigned int height;
+ unsigned int frames_sec;
+ unsigned int total_frames;
+ unsigned int type;
+} ThreadParams;
+
+typedef enum
+{
+ None = 0,
+ InitParams = 1, /* Length (4 bytes) + pixels */
+ NewImage = 2, /* Length (4 bytes) seconds */
+ FixedImage = 3, /* Length (4 bytes) + nframes + pixels */
+ End = 4
+} Command;
+
+void mistelix_socket_send (unsigned char* data, unsigned int bytes);
+void mistelix_socket_connect ();
+gpointer mistelix_launch_gstreamer (gpointer data);
+
+const gchar* address = "localhost";
+const int port = 2048;
+static int mis_socket;
+ThreadParams params;
+char audio[1024];
+GThread* thread;
+int started;
+
+// It is assumed that there is only one client using the library at the time
+// There are no handles for session, just the active session
+
+void
+mistelix_slideshow_createstream (const gchar* filename, unsigned int type, unsigned int weight, unsigned int height, unsigned int frames_sec, unsigned int total_frames)
+{
+#ifdef _DEBUG
+ printf ("*** mistelix_slideshow_createstream: %s, %u, %u, %u, %u\n", filename, type, weight, height, frames_sec);
+#endif
+ thread = NULL;
+ started = 0;
+ *audio = '\x0';
+ strcpy ((char*) params.filename,filename);
+ params.weight = weight;
+ params.height = height;
+ params.frames_sec = frames_sec;
+ params.total_frames = total_frames;
+ params.type = type;
+}
+
+void
+mistelix_slideshow_add_image (unsigned char* bytes, unsigned int len)
+{
+ unsigned char header[6];
+ unsigned char* pos = (unsigned char*) &len;
+ int i;
+#ifdef _DEBUG
+ printf ("*** mistelix_slideshow_add_image %x\n", len);
+#endif
+ mistelix_check_started ();
+
+ // Command
+ header[0] = 0xff;
+ header[1] = NewImage;
+
+ // Len
+ for (i = 0; i < sizeof (unsigned int); i++) {
+ header[2 + i] = *pos;
+ pos++;
+ }
+
+ mistelix_socket_send (header, 6);
+ mistelix_socket_send (bytes, len);
+}
+
+void
+mistelix_slideshow_add_imagefixed (unsigned char* bytes, unsigned int len, unsigned int frames)
+{
+ unsigned char header[10]; // 2 bytes header, 4 length buffer, 4 number of frames
+ unsigned char* pos = (unsigned char*) &len;
+ int i;
+#ifdef _DEBUG
+ printf ("*** mistelix_slideshow_add_image_fixed %x %u\n", len, frames);
+#endif
+ mistelix_check_started ();
+
+ // Command
+ header[0] = 0xff;
+ header[1] = FixedImage;
+
+ // Len
+ for (i = 0; i < sizeof (unsigned int); i++) {
+ header[2 + i] = *pos;
+ pos++;
+ }
+
+ // Frames
+ pos = (unsigned char*) &frames;
+ for (i = 0; i < sizeof (unsigned int); i++) {
+ header[6 + i] = *pos;
+ pos++;
+ }
+
+ mistelix_socket_send (header, 10);
+ mistelix_socket_send (bytes, len);
+}
+
+
+void
+mistelix_slideshow_close ()
+{
+ // Wait until the pipe line completes
+ g_thread_join (thread);
+}
+
+
+void
+mistelix_slideshow_add_audio (const gchar* filename)
+{
+ strcpy (audio, filename);
+
+/*
+ Private functions
+*/
+
+}
+/* Sends a seek event to a pad */
+void
+send_seek_event (GstElement* pipeline, GstPad* pad, gboolean flush)
+{
+ gboolean res = FALSE;
+ GstEvent *event;
+ GstSeekFlags flags;
+
+ flags = GST_SEEK_FLAG_SEGMENT;
+
+ if (flush)
+ flags |= GST_SEEK_FLAG_FLUSH;
+
+ /* Seek from the begining */
+ event = gst_event_new_seek (1, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1);
+ res = gst_pad_send_event (pad, event);
+ if (res)
+ gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, SEEK_TIMEOUT);
+ else
+ printf ("send_seek_event: error sending seek event\n");
+}
+
+/*
+ Monitor the EOS event for the sink pad
+ and resend it to the pipeline to finish it
+*/
+static gboolean
+gst_handle_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstElement* element = (GstElement *) gst_object_get_parent (GST_OBJECT (pad));
+
+#ifdef _DEBUG
+ printf ("--->* gst_handle_sink_event %s %s -> %s (%u)\n",
+ gst_element_get_name (element),
+ gst_element_get_name (pad),
+ gst_event_type_get_name (event->type),
+ event->type);
+#endif
+ if (event->type == GST_EVENT_EOS) {
+ GstElement* pipe = (GstElement *) gst_object_get_parent (GST_OBJECT (element));
+ GstBus *bus = gst_element_get_bus (pipe);
+ gst_bus_post (bus, gst_message_new_eos (GST_OBJECT (pipe)));
+#ifdef _DEBUG
+ printf ("Posted EOS\n");
+#endif
+ }
+ return gst_pad_event_default (pad, event);
+}
+
+
+/*
+ Do not want to start the thread until is necessary
+ to allow for example to add an audio channel before launching it
+*/
+void
+mistelix_check_started ()
+{
+ if (started != 0)
+ return;
+
+ started = 1;
+
+ thread = g_thread_create (mistelix_launch_gstreamer, (gpointer) ¶ms, TRUE, NULL);
+ // TODO: To be replaced by socket timeout
+ sleep (2);
+ mistelix_socket_connect ();
+}
+
+
+#ifdef _DEBUG
+
+/*
+ Lists all the elements in a pipeline
+*/
+void
+listelements (GstBin* bin)
+{
+ gpointer point, point_pad;
+ GstIterator *it, *it_pads;
+
+ it = gst_bin_iterate_elements (bin);
+
+ printf ("----\n");
+ while (gst_iterator_next (it, &point) == GST_ITERATOR_OK) {
+ GstElement* element = GST_ELEMENT (point);
+
+ it_pads = gst_element_iterate_pads (element);
+ printf ("element -> %s\n", gst_element_get_name (element));
+
+ while (gst_iterator_next (it_pads, &point_pad) == GST_ITERATOR_OK) {
+ GstPad * pad = GST_PAD (point_pad);
+ printf ("pad-> %s\n", gst_element_get_name (pad));
+ }
+ }
+ printf ("----\n");
+}
+#endif
+
+gboolean
+mistelix_is_codec (const char* name)
+{
+ int ncodecs, i;
+ gboolean found = FALSE;
+
+ ncodecs = mistelix_get_plugins_count ();
+
+ char *plugins[ncodecs];
+ mistelix_get_plugins (plugins);
+
+ for (i = 0; i < ncodecs; i++ )
+ {
+ if (strcmp (name, plugins[i]) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ for (i = 0; i < ncodecs; i++)
+ free (plugins [i]);
+
+#ifdef _DEBUG
+ printf ("Codec %s, found %d\n", name, found);
+#endif
+ return found;
+}
+
+/*
+ Get the element name within the pipeline
+ Caller is responsible for freezing the allocated memory
+*/
+char *
+mistelix_get_element_name_from_pipeline (GstBin* pipe, char* generic_name)
+{
+ char* result = NULL;
+ gpointer point;
+ GstIterator* it;
+ int len;
+
+ len = strlen (generic_name);
+ it = gst_bin_iterate_elements (pipe);
+
+ while (gst_iterator_next (it, &point) == GST_ITERATOR_OK) {
+ GstElement* element = GST_ELEMENT (point);
+ char* name;
+
+ name = gst_element_get_name (element);
+
+ if (strncmp (name, generic_name, len) == 0) {
+ result = malloc (strlen (name) + 1);
+ strcpy (result, name);
+ break;
+ }
+ }
+#ifdef _DEBUG
+ printf ("Seached %s, found %s\n", generic_name, result);
+#endif
+ return result;
+}
+
+/* Method to launch gstreamer thread. Method signature as required by g_thread_create */
+gpointer
+mistelix_launch_gstreamer (gpointer data)
+{
+ char desc [1024];
+ GstElement* pipe, *element;
+ ThreadParams* params = (ThreadParams *) data;
+ gboolean has_audio;
+ GstBus *bus;
+ GstMessage *message;
+ GstStateChangeReturn ret;
+ GstPad* seekable_pad;
+ gpointer point_pad;
+ GstIterator *it_pads;
+ char* element_name;
+ int sink = 0;
+ gboolean vorbis = FALSE;
+ char media [2048];
+
+ mistelix_check_init ();
+
+ has_audio = (*audio != '\x0');
+
+ if (has_audio) {
+ mistelix_detect_media (audio, media);
+
+ if (strcmp (media, "application/ogg") == 0) {
+ if (mistelix_is_codec ("vorbisdec"))
+ vorbis = TRUE;
+ else
+ has_audio = FALSE;
+ } else {
+ if (strcmp (media, "application/x-id3") == 0) {
+ if (mistelix_is_codec ("flump3dec"))
+ vorbis = FALSE;
+ else
+ has_audio = FALSE;
+ } else {
+ printf ("mistelix: unsupported audio format: %s\n", media);
+ has_audio = FALSE;
+ }
+ }
+ }
+
+ if (params->type == 0) {/* Theora output format */
+ if (has_audio) {
+ if (vorbis) { /* Source audio in Vorbis */
+ sprintf (desc,
+ "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
+ "theoraenc ! mux. filesrc location=\"%s\" ! oggdemux ! vorbisdec ! audioconvert ! vorbisenc ! "
+ "oggmux name=mux ! filesink location=\"%s\"",
+ params->total_frames, params->weight, params->height, params->frames_sec, audio, params->filename);
+ } else { /* Source audio in MP3 */
+ sprintf (desc,
+ "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
+ "theoraenc ! mux. filesrc location=\"%s\" ! flump3dec ! audioconvert ! vorbisenc ! "
+ "oggmux name=mux ! filesink location=\"%s\"",
+ params->total_frames, params->weight, params->height, params->frames_sec, audio, params->filename);
+ }
+ } else {
+ sprintf (desc,
+ "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
+ "theoraenc ! oggmux !filesink location=\"%s\"",
+ params->total_frames, params->weight, params->height, params->frames_sec, params->filename);
+ }
+ }
+ else { /* DVD output format */
+
+ /*
+ * ffenc_mpeg2video
+ * We use 'bitrate'element to set the quality of the generated MPEG2 video.
+ * Every additional 10000 bits/s represent approximately 10% additional time
+ * to generate the video
+ *
+ * ffmux_dvd
+ * We use maxdelay and preload to generate MPEG2 compatible streams with DVD
+ */
+
+ /* No audio support for now */
+ sprintf (desc,
+ "mistelixvideosrc num-buffers=%u ! video/x-raw-yuv,format=(fourcc)I420,width=%u,height=%u,framerate=(fraction)%u/1 !"
+ "ffenc_mpeg2video bitrate=500000 ! ffmux_dvd preload=500000 maxdelay=699999 !filesink location=\"%s\"",
+ params->total_frames, params->weight, params->height, params->frames_sec, params->filename);
+ }
+#ifdef _DEBUG
+ printf ("mistelix_launch_gstreamer: %s\n", desc);
+#endif
+ pipe = gst_parse_launch (desc, NULL);
+
+ /* Launch pipeline */
+
+#ifdef _DEBUG
+ listelements (GST_BIN (pipe));
+ printf ("*** run_pipeline start\n");
+#endif
+
+ g_assert (pipe);
+ bus = gst_element_get_bus (pipe);
+ g_assert (bus);
+
+ gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+ /* Wait for status change */
+ gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
+
+ if (has_audio) {
+
+ /* Find the pad of the audio decoder to send the audio seek events */
+ if (vorbis)
+ element_name = mistelix_get_element_name_from_pipeline (GST_BIN (pipe), "vorbisdec");
+ else
+ element_name = mistelix_get_element_name_from_pipeline (GST_BIN (pipe), "flump3dec");
+
+ g_assert (element_name);
+ element = gst_bin_get_by_name (GST_BIN (pipe), element_name);
+ free (element_name);
+
+ g_assert (element);
+ seekable_pad = gst_element_get_pad (element, "src");
+ g_assert (seekable_pad);
+
+ /* Find the muxer's sink's and set callback function */
+ element = gst_bin_get_by_name (GST_BIN (pipe), "mux");
+ g_assert (element);
+
+ it_pads = gst_element_iterate_pads (element);
+ while (gst_iterator_next (it_pads, &point_pad) == GST_ITERATOR_OK) {
+ GstPad * pad = GST_PAD (point_pad);
+
+ if (strncmp (gst_element_get_name (pad), "src", 3) == 0)
+ continue;
+
+ sink++;
+ if (sink < 2)
+ continue;
+
+ /* The second sink is the video sink */
+ #ifdef _DEBUG
+ printf ("Setting handler for %s\n", gst_element_get_name (pad));
+ #endif
+ gst_pad_set_event_function (pad, gst_handle_sink_event);
+ break;
+ }
+
+ send_seek_event (pipe, seekable_pad, FALSE);
+ }
+ /* We get a GST_MESSAGE_EOS when the pipe is finished */
+ while (1) {
+ GstMessageType revent;
+
+ message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+
+ if (message) {
+ revent = GST_MESSAGE_TYPE (message);
+#ifdef _DEBUG
+ printf ("*** run_pipeline message: %s (%x)\n", gst_message_type_get_name (revent), revent);
+#endif
+ gst_message_unref (message);
+ } else
+ revent = GST_MESSAGE_UNKNOWN;
+
+ if (revent == GST_MESSAGE_SEGMENT_DONE) {
+ /* Send audio segment again */
+ send_seek_event (pipe, seekable_pad, TRUE);
+ continue;
+ }
+
+ if (revent == GST_MESSAGE_ERROR) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason GST_MESSAGE_ERROR\n");
+#endif
+ break;
+ }
+
+ if (revent == GST_MESSAGE_EOS) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason: GST_MESSAGE_EOS\n");
+#endif
+ break;
+ }
+ }
+
+ /* Need to explicitly set elements to the NULL state before dropping the final reference */
+ gst_element_set_state (pipe, GST_STATE_NULL);
+ gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
+ gst_object_unref (pipe);
+ gst_object_unref (bus);
+
+#ifdef _DEBUG
+ printf ("*** run_pipeline end\n");
+#endif
+ return NULL;
+}
+
+void
+mistelix_socket_connect ()
+{
+ struct sockaddr_in serveraddr;
+ int yes = 1;
+#ifdef _DEBUG
+ printf ("*** mistelix_socket_connect %s %u\n", address, port);
+#endif
+ if ((mis_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ return;
+
+ if (setsockopt (mis_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
+ {
+ close (mis_socket);
+ return;
+ }
+
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_addr.s_addr = INADDR_ANY;
+ serveraddr.sin_port = htons (port);
+ memset (&(serveraddr.sin_zero), '\0', 8);
+
+ if (connect (mis_socket,(struct sockaddr *)&serveraddr,sizeof (serveraddr)) < 0)
+ {
+ printf ("*** mistelix_socket_connect error. It may be caused because not all the assumed pipe elements are present\n");
+ return;
+ }
+
+ printf ("*** mistelix_socket_connect %d\n", mis_socket);
+}
+
+void
+mistelix_socket_send (unsigned char* data, unsigned int bytes)
+{
+ write (mis_socket, data, bytes);
+}
+
diff --git a/libmistelix/typefind.c b/libmistelix/typefind.c
new file mode 100644
index 0000000..6306084
--- /dev/null
+++ b/libmistelix/typefind.c
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include <stdio.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <gst/gst.h>
+#include <sys/wait.h>
+
+#include "mistelix.h"
+
+
+
+static void
+cb_typefound (GstElement *typefind,
+ guint probability,
+ GstCaps *caps,
+ gpointer data)
+{
+ gchar *type;
+ char* media_type = (char*) data;
+
+ type = gst_caps_to_string (caps);
+
+//#ifdef _DEBUG
+ printf ("Media type %s found, probability %d%%, %x\n", type, probability, (unsigned int) caps);
+//#endif
+ if (caps!= NULL && type != NULL)
+ strcpy (media_type, type);
+
+ g_free (type);
+}
+
+
+void
+mistelix_detect_media (const char* file, char* media)
+{
+ GstElement* pipe, *filesrc, *typefind, *fakesink;
+ GstBus *bus;
+ char media_type [2048];
+
+ mistelix_check_init ();
+
+ pipe = gst_pipeline_new ("pipe");
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
+ gst_object_unref (bus);
+
+ // create file source and typefind element
+ filesrc = gst_element_factory_make ("filesrc", "source");
+ g_object_set (G_OBJECT (filesrc), "location", file, NULL);
+ typefind = gst_element_factory_make ("typefind", "typefinder");
+ g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), (gpointer) media_type);
+ fakesink = gst_element_factory_make ("fakesink", "sink");
+
+ gst_bin_add_many (GST_BIN (pipe), filesrc, typefind, fakesink, NULL);
+ gst_element_link_many (filesrc, typefind, fakesink, NULL);
+
+ gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_PLAYING);
+ /* Wait for status change */
+ gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
+
+ gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (pipe));
+ strcpy (media, media_type);
+
+ printf ("*** mistelix_detect_media result for %s is [%s]\n", file, media);
+}
+
diff --git a/libmistelix/video.c b/libmistelix/video.c
index 3ad3421..616f7e6 100644
--- a/libmistelix/video.c
+++ b/libmistelix/video.c
@@ -31,6 +31,8 @@ typedef struct
const char *pipeline;
} supported_media;
+void run_pipeline (GstElement * pipe);
+
supported_media supported_medias[] =
{
//
@@ -70,14 +72,14 @@ mistelix_video_extensions (char* extensions)
}
int
-mistelix_media_supported (const char* file, char* msg)
+mistelix_video_supported (const char* file, char* msg)
{
char media [2048];
int i, ncodecs, c, media_present, plugin_present;
char* pos;
//#ifdef _DEBUG
- printf ("*** mistelix_media_supported %s\n", file);
+ printf ("*** mistelix_video_supported %s\n", file);
//#endif
mistelix_detect_media (file, media);
@@ -90,9 +92,9 @@ mistelix_media_supported (const char* file, char* msg)
if (*media == 0x0)
return 1; // Could not identify media
- ncodecs = mistelix_get_codecs_count ();
+ ncodecs = mistelix_get_plugins_count ();
char *codecs[ncodecs];
- mistelix_get_codecs (codecs);
+ mistelix_get_plugins (codecs);
media_present = plugin_present = 0;
for (i = 0; i < sizeof (supported_medias) / sizeof (supported_media); i++)
@@ -129,7 +131,7 @@ mistelix_media_supported (const char* file, char* msg)
}
int
-mistelix_convert_media (const char* filein, const char* fileout, unsigned int frames_sec)
+mistelix_video_convert (const char* filein, const char* fileout, unsigned int frames_sec)
{
char media [2048];
int i, ncodecs, c, media_present, plugin_present;
@@ -149,9 +151,9 @@ mistelix_convert_media (const char* filein, const char* fileout, unsigned int fr
if (*media == 0x0)
return 1; // Could not identify media
- ncodecs = mistelix_get_codecs_count ();
+ ncodecs = mistelix_get_plugins_count ();
char *codecs[ncodecs];
- mistelix_get_codecs (codecs);
+ mistelix_get_plugins (codecs);
media_present = plugin_present = 0;
for (i = 0; i < sizeof (supported_medias) / sizeof (supported_media); i++)
@@ -192,62 +194,69 @@ mistelix_convert_media (const char* filein, const char* fileout, unsigned int fr
}
-//
-// Private
-//
+/*
+ Private functions
+*/
+
+/*
+ Runs standard pipline that ends by an EOS event
+*/
void
-mistelix_detect_media (const char* file, char* media)
+run_pipeline (GstElement * pipe)
{
- GstElement* pipe, *filesrc, *typefind, *fakesink;
GstBus *bus;
- char media_type [2048];
-
- mistelix_check_init ();
-
- pipe = gst_pipeline_new ("pipe");
- bus = gst_pipeline_get_bus (GST_PIPELINE (pipe));
- gst_object_unref (bus);
+ GstMessage *message;
+ GstMessageType revent;
+ GstStateChangeReturn ret;
- // create file source and typefind element
- filesrc = gst_element_factory_make ("filesrc", "source");
- g_object_set (G_OBJECT (filesrc), "location", file, NULL);
- typefind = gst_element_factory_make ("typefind", "typefinder");
- g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), (gpointer) media_type);
- fakesink = gst_element_factory_make ("fakesink", "sink");
+#ifdef _DEBUG
+ printf ("*** run_pipeline start\n");
+#endif
+ g_assert (pipe);
+ bus = gst_element_get_bus (pipe);
+ g_assert (bus);
- gst_bin_add_many (GST_BIN (pipe), filesrc, typefind, fakesink, NULL);
- gst_element_link_many (filesrc, typefind, fakesink, NULL);
+ gst_element_set_state (pipe, GST_STATE_PLAYING);
- gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_PLAYING);
/* Wait for status change */
- gst_element_get_state (pipe, NULL, NULL, SEEK_TIMEOUT);
-
- gst_element_set_state (GST_ELEMENT (pipe), GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (pipe));
- strcpy (media, media_type);
+ gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
- printf ("*** mistelix_detect_media result for %s is [%s]\n", file, media);
-}
+ /* We get a GST_MESSAGE_EOS when the pipe is finished */
+ while (1) {
+ message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
+ if (message) {
+ revent = GST_MESSAGE_TYPE (message);
+#ifdef _DEBUG
+ printf ("*** run_pipeline message: %s (%x)\n", gst_message_type_get_name (revent), revent);
+#endif
+ gst_message_unref (message);
+ } else
+ revent = GST_MESSAGE_UNKNOWN;
-static void
-cb_typefound (GstElement *typefind,
- guint probability,
- GstCaps *caps,
- gpointer data)
-{
- gchar *type;
- char* media_type = (char*) data;
+ if (revent == GST_MESSAGE_ERROR) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason GST_MESSAGE_ERROR\n");
+#endif
+ break;
+ }
- type = gst_caps_to_string (caps);
+ if (revent == GST_MESSAGE_EOS) {
+#ifdef _DEBUG
+ printf ("*** run_pipeline exiting reason: GST_MESSAGE_EOS\n");
+#endif
+ break;
+ }
+ }
-//#ifdef _DEBUG
- printf ("Media type %s found, probability %d%%, %x\n", type, probability, (unsigned int) caps);
-//#endif
- if (caps!= NULL && type != NULL)
- strcpy (media_type, type);
+ gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
+ //gst_object_unref (pipe);
- g_free (type);
+ gst_bus_set_flushing (bus, TRUE);
+ //gst_object_unref (bus);
+#ifdef _DEBUG
+ printf ("*** run_pipeline end\n");
+#endif
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8b3c65d..65395c9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,9 +10,9 @@ extensions/SlideTransitions/StarWipe/StarWipeFivePoint.cs
extensions/SlideTransitions/StarWipe/StarWipeFourPoint.cs
extensions/SlideTransitions/StarWipe/StarWipeSixPoint.cs
mistelix.desktop.in
+src/Backends/GStreamer/Video.cs
src/Core/Dependencies.cs
src/Core/DvdProjectBuilder.cs
-src/Core/MistelixLib.cs
src/Core/NoneTransition.cs
src/Core/ResolutionManager.cs
src/Core/SlideShowsProjectBuilder.cs
diff --git a/src/Backends/GStreamer/Plugins.cs b/src/Backends/GStreamer/Plugins.cs
new file mode 100644
index 0000000..04d0ffa
--- /dev/null
+++ b/src/Backends/GStreamer/Plugins.cs
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using Mistelix.Core;
+
+namespace Mistelix.Backends.GStreamer
+{
+ //
+ // GStreamer plugin enumeration functions
+ //
+ public static class Plugins
+ {
+ [DllImport ("libmistelix")]
+ static extern uint mistelix_get_plugins_count ();
+
+ [DllImport ("libmistelix")]
+ static extern IntPtr mistelix_get_plugins (IntPtr [] plugins);
+
+ static Plugins ()
+ {
+
+ }
+
+ static public List <string> GetList ()
+ {
+ uint count;
+ IntPtr[] list;
+ string codec;
+ List <string> codecs = new List <string> ();
+
+ count = mistelix_get_plugins_count ();
+ Logger.Debug ("Plugin.GetList. Gstreamer pluggins: {0}", count);
+ list = new IntPtr [count];
+ mistelix_get_plugins (list);
+
+ for (int i = 0; i < count; i++)
+ {
+ codec = Marshal.PtrToStringAuto (list[i]);
+ codecs.Add (codec);
+ Marshal.FreeHGlobal (list[i]);
+ }
+ return codecs;
+ }
+ }
+}
diff --git a/src/Backends/GStreamer/SlideShow.cs b/src/Backends/GStreamer/SlideShow.cs
new file mode 100644
index 0000000..2142dbe
--- /dev/null
+++ b/src/Backends/GStreamer/SlideShow.cs
@@ -0,0 +1,125 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+using Mistelix.DataModel;
+
+namespace Mistelix.Backends.GStreamer
+{
+ //
+ // GStreamer slideshow functions
+ //
+ public static class SlideShow
+ {
+ [DllImport ("libmistelix")]
+ static extern int mistelix_slideshow_createstream (string filename, uint type, uint weight, uint height, uint framessec, uint totalframes);
+
+ [DllImport ("libmistelix")]
+ static extern int mistelix_slideshow_add_image (IntPtr bytes, uint len);
+
+ [DllImport ("libmistelix")]
+ static extern int mistelix_slideshow_add_imagefixed (IntPtr bytes, uint len, uint frames);
+
+ [DllImport ("libmistelix")]
+ static extern void mistelix_slideshow_add_audio (string filename);
+
+ [DllImport ("libmistelix")]
+ static extern void mistelix_slideshow_close ();
+
+ static SlideShow ()
+ {
+
+ }
+
+ static public int CreateStream (string filename, ProjectType type, uint weight, uint height, uint framessec, uint totalframes)
+ {
+ return mistelix_slideshow_createstream (filename, (uint) type, weight, height, framessec, totalframes);
+ }
+
+ static public int AddImage (SlideImage image)
+ {
+ IntPtr pixels = IntPtr.Zero;
+ int rslt = -1;
+
+ try
+ {
+ if (image.Channels != 3)
+ throw new InvalidOperationException (String.Format ("mistelixvideosrc expects images in 24 bits (3 channels) not {0}", image.Channels));
+
+ pixels = Marshal.AllocHGlobal (image.Pixels.Length);
+ Marshal.Copy (image.Pixels, 0, pixels, image.Pixels.Length);
+
+ rslt = mistelix_slideshow_add_image (pixels, (uint) image.Pixels.Length);
+ return rslt;
+ }
+
+ finally
+ {
+ Marshal.FreeHGlobal (pixels);
+ }
+ }
+
+ static public int AddImageFixed (SlideImage image, uint frames)
+ {
+ IntPtr pixels = IntPtr.Zero;
+ int rslt = -1;
+
+ try
+ {
+ if (image.Channels != 3)
+ throw new InvalidOperationException (String.Format ("mistelixvideosrc expects images in 24 bits (3 channels) not {0}", image.Channels));
+
+ pixels = Marshal.AllocHGlobal (image.Pixels.Length);
+ Marshal.Copy (image.Pixels, 0, pixels, image.Pixels.Length);
+
+ rslt = mistelix_slideshow_add_imagefixed (pixels, (uint) image.Pixels.Length, frames);
+ return rslt;
+ }
+
+ finally
+ {
+ Marshal.FreeHGlobal (pixels);
+ }
+ }
+
+ static public void AddAudio (string file)
+ {
+ try
+ {
+ mistelix_slideshow_add_audio (file);
+ }
+
+ finally
+ {
+
+ }
+ }
+
+ static public void Close ()
+ {
+ mistelix_slideshow_close ();
+ }
+ }
+}
diff --git a/src/Backends/GStreamer/Thumbnail.cs b/src/Backends/GStreamer/Thumbnail.cs
new file mode 100644
index 0000000..8554a72
--- /dev/null
+++ b/src/Backends/GStreamer/Thumbnail.cs
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.InteropServices;
+using Gdk;
+
+namespace Mistelix.Backends.GStreamer
+{
+ //
+ // GStreamer video thumbnailing functions
+ //
+ public static class Thumbnail
+ {
+ [DllImport ("libmistelix")]
+ static extern void mistelix_video_screenshot (string filein, out IntPtr pixbuf);
+
+
+ static Thumbnail ()
+ {
+
+ }
+
+ static public Gdk.Pixbuf VideoScreenshot (string file)
+ {
+ Gdk.Pixbuf thumbnail;
+ IntPtr pix;
+
+ mistelix_video_screenshot (file, out pix);
+
+ if (pix == IntPtr.Zero)
+ throw new InvalidOperationException ("No screenshot taken");
+
+ thumbnail = new Gdk.Pixbuf (pix);
+ return thumbnail;
+ }
+ }
+}
diff --git a/src/Backends/GStreamer/Video.cs b/src/Backends/GStreamer/Video.cs
new file mode 100644
index 0000000..4d33f04
--- /dev/null
+++ b/src/Backends/GStreamer/Video.cs
@@ -0,0 +1,123 @@
+//
+// Copyright (C) 2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Mono.Unix;
+
+using Mistelix.Core;
+
+namespace Mistelix.Backends.GStreamer
+{
+ //
+ // GStreamer video functions
+ //
+ public static class Video
+ {
+ [DllImport ("libmistelix")]
+ static extern void mistelix_video_extensions (StringBuilder extensions);
+
+ [DllImport ("libmistelix")]
+ static extern int mistelix_video_supported (string file, StringBuilder media);
+
+ [DllImport ("libmistelix")]
+ static extern int mistelix_video_convert (string filein, string fileout, uint frames_sec);
+
+ static string [] extensions;
+
+ static Video ()
+ {
+
+ }
+
+ static public string[] FileExtensions ()
+ {
+ if (extensions != null)
+ return extensions;
+
+ List <string> strs = new List <string> ();
+ string rslt;
+ int pos;
+ StringBuilder sb = new StringBuilder (1024);
+
+ mistelix_video_extensions (sb);
+ rslt = sb.ToString ();
+
+ while (true) {
+ rslt = rslt.TrimStart ();
+ pos = rslt.IndexOf (";");
+
+ if (pos == -1) {
+ if (rslt.Length > 0)
+ strs.Add (rslt);
+ break;
+ }
+
+ strs.Add (rslt.Substring (0, pos));
+ pos++;
+ rslt = rslt.Substring (pos);
+ }
+ extensions = strs.ToArray ();
+ return extensions;
+ }
+
+ static public bool IsSupported (string file, out string msg)
+ {
+ int r;
+ StringBuilder rslt = new StringBuilder (2048);
+
+ r = mistelix_video_supported (file, rslt);
+ Logger.Debug ("MistelixLib.IsMediaSupported. File {0} is {1}", file, r);
+
+ switch (r) {
+ case 0: // Format supported
+ msg = string.Empty;
+ return true;
+ case 1: // Could not identify media
+ msg = String.Format (Catalog.GetString ("Could not identify media type for file '{0}'"), file);
+ return false;
+ case 2: // Format not supported
+ msg = String.Format (Catalog.GetString ("The file '{0}' is encoded in an unsupported format"), file);
+ return false;
+ case 3: // Supported media but codec not found + codec name
+ msg = String.Format (Catalog.GetString ("The file '{0}' is encoded in a recognised format. However, you are missing the GStreamer plug-in '{1}' to decode it."), file, rslt);
+ return false;
+ default:
+ throw new Exception ("Unexpected result");
+ }
+ }
+
+ static public bool Convert (string filein, string fileout, uint frames_sec)
+ {
+ int rslt = mistelix_video_convert (filein, fileout, frames_sec);
+
+ if (rslt == 0)
+ return true;
+
+ return false;
+ }
+
+ }
+}
diff --git a/src/Backends/OS/Unix.cs b/src/Backends/OS/Unix.cs
new file mode 100644
index 0000000..41b1882
--- /dev/null
+++ b/src/Backends/OS/Unix.cs
@@ -0,0 +1,93 @@
+//
+// Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas softcatala org
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+using Mistelix.DataModel;
+using Mistelix.Core;
+
+namespace Mistelix.Backends.OS
+{
+ //
+ // Unix specific functions
+ //
+ public static class Unix
+ {
+ [DllImport ("libmistelix")]
+ static extern void mistelix_launchtool (string app, string args, string in_file, string out_file, string err_file);
+
+ static Unix ()
+ {
+
+ }
+
+ // There is no SpecialFolder support for videos. We have to read the xdg configuration directly
+ public static string GetDefaultVideoDirectory ()
+ {
+ string directory = null, line;
+ const string home = "$HOME/";
+ const string key = "XDG_VIDEOS_DIR";
+ string home_dir = Environment.GetEnvironmentVariable ("HOME");
+ string config_file;
+
+ try {
+ config_file = Path.Combine (home_dir, ".config/user-dirs.dirs");
+
+ using (StreamReader reader = new StreamReader (config_file))
+ {
+ while ((line = reader.ReadLine ()) != null)
+ {
+ line = line.Trim ();
+ int pos = line.IndexOf ('=');
+ if (pos > 8 && line.Substring (0, pos) == key) {
+ string path = line.Substring (pos + 1).Trim ('"');
+ bool relative = false;
+
+ if (path.StartsWith (home)) {
+ relative = true;
+ path = path.Substring (home.Length);
+ } else if (!path.StartsWith ("/"))
+ relative = true;
+
+ directory = relative ? Path.Combine (home_dir, path) : path;
+ break;
+ }
+ }
+ }
+ }
+ catch (Exception) { }
+
+ if (directory == null)
+ return Environment.GetFolderPath (Environment.SpecialFolder.Personal);
+ else
+ return directory;
+ }
+
+ static public void LaunchTool (string app, string args, string in_file, string out_file, string err_file)
+ {
+ mistelix_launchtool (app, args, in_file, out_file, err_file);
+ }
+ }
+}
diff --git a/src/Core/Dependencies.cs b/src/Core/Dependencies.cs
index 0300b11..0e7c1d7 100644
--- a/src/Core/Dependencies.cs
+++ b/src/Core/Dependencies.cs
@@ -28,6 +28,7 @@ using System.Diagnostics;
using Mistelix.Transitions;
using Mistelix.DataModel;
+using Mistelix.Backends.GStreamer;
namespace Mistelix.Core
{
@@ -128,7 +129,7 @@ namespace Mistelix.Core
return;
status_checked = true;
- List <string> codecs = MistelixLib.GetCodecs ();
+ List <string> codecs = Plugins.GetList ();
string [] used = {"ffenc_mpeg2video", "ffmux_dvd", "mistelixvideosrc", "theoraenc", "oggmux", "vorbisdec", "flump3dec", "asfdemux"};
bool [] founds = new bool [used.Length];
diff --git a/src/Core/DvdProjectBuilder.cs b/src/Core/DvdProjectBuilder.cs
index ab57e9f..4981cad 100644
--- a/src/Core/DvdProjectBuilder.cs
+++ b/src/Core/DvdProjectBuilder.cs
@@ -32,6 +32,7 @@ using Mistelix.Widgets;
using Mistelix.DataModel;
using Mistelix.Core;
using Mistelix.Backends;
+using Mistelix.Backends.OS;
using Mistelix.Dialogs;
namespace Mistelix.Core
@@ -123,7 +124,7 @@ namespace Mistelix.Core
sp.Create ();
//LaunchTool (string app, string args, string in_file, string out_file, string err_file);
- MistelixLib.LaunchTool ("spumux",
+ Unix.LaunchTool ("spumux",
project.FileToFullPath (Defines.SPUMUX_FILE),
project.FileToFullPath (Defines.MAIN_MENU_FILE_SRC),
project.FileToFullPath (Defines.MAIN_MENU_FILE),
@@ -147,7 +148,7 @@ namespace Mistelix.Core
string args = String.Format ("-x{0}", project.FileToFullPath (Defines.DVDAUTHOR_FILE));
- MistelixLib.LaunchTool ("dvdauthor",
+ Unix.LaunchTool ("dvdauthor",
args,
null,
null,
diff --git a/src/Core/Preferences.cs b/src/Core/Preferences.cs
index 3607766..b1769bf 100644
--- a/src/Core/Preferences.cs
+++ b/src/Core/Preferences.cs
@@ -29,6 +29,7 @@ using System.Text;
using System.Diagnostics;
using Mistelix.DataModel;
+using Mistelix.Backends.OS;
namespace Mistelix.Core
{
@@ -191,7 +192,7 @@ namespace Mistelix.Core
Environment.GetFolderPath (Environment.SpecialFolder.MyPictures));
properties.Add (VideosDirectoryKey,
- GetDefaultVideoDirectory ());
+ Unix.GetDefaultVideoDirectory ());
properties.Add (AudioDirectoryKey,
Environment.GetFolderPath (Environment.SpecialFolder.MyMusic));
@@ -231,47 +232,5 @@ namespace Mistelix.Core
Logger.Error (String.Format ("Preferences.Load. Error loading preferences {0}", e.Message));
}
}
-
- // There is no SpecialFolder support for videos. We have to read the xdg configuration directly
- static string GetDefaultVideoDirectory ()
- {
- string directory = null, line;
- const string home = "$HOME/";
- const string key = "XDG_VIDEOS_DIR";
- string home_dir = Environment.GetEnvironmentVariable ("HOME");
- string config_file;
-
- try {
- config_file = Path.Combine (home_dir, ".config/user-dirs.dirs");
-
- using (StreamReader reader = new StreamReader (config_file))
- {
- while ((line = reader.ReadLine ()) != null)
- {
- line = line.Trim ();
- int pos = line.IndexOf ('=');
- if (pos > 8 && line.Substring (0, pos) == key) {
- string path = line.Substring (pos + 1).Trim ('"');
- bool relative = false;
-
- if (path.StartsWith (home)) {
- relative = true;
- path = path.Substring (home.Length);
- } else if (!path.StartsWith ("/"))
- relative = true;
-
- directory = relative ? Path.Combine (home_dir, path) : path;
- break;
- }
- }
- }
- }
- catch (Exception) { }
-
- if (directory == null)
- return Environment.GetFolderPath (Environment.SpecialFolder.Personal);
- else
- return directory;
- }
}
}
diff --git a/src/Core/SlideShow.cs b/src/Core/SlideShow.cs
index f811b4c..983011c 100644
--- a/src/Core/SlideShow.cs
+++ b/src/Core/SlideShow.cs
@@ -26,6 +26,7 @@ using System;
using Mistelix.Transitions;
using Mistelix.Core;
using Mistelix.DataModel;
+using Mistelix.Backends.GStreamer;
namespace Mistelix.Core
{
@@ -41,7 +42,6 @@ namespace Mistelix.Core
public string Generate (Project project, ProgressEventHandler progress)
{
- MistelixLib lib = new MistelixLib ();
int total_frames = 0;
int frames_sec = project.Details.FramesPerSecond;
ProgressEventArgs args = new ProgressEventArgs ();
@@ -65,12 +65,12 @@ namespace Mistelix.Core
else
outfile = filename;
- lib.SlideShowCreateStream (project.FileToFullPath (outfile), project.Details.Type,
+ Backends.GStreamer.SlideShow.CreateStream (project.FileToFullPath (outfile), project.Details.Type,
(uint) project.Details.Width, (uint) project.Details.Height, (uint) frames_sec, (uint) total_frames);
if (AudioFile != null) {
Logger.Debug ("SlideShow.Generate. Audiofile {0}", AudioFile);
- lib.SlideShowAddAudio (AudioFile);
+ Backends.GStreamer.SlideShow.AddAudio (AudioFile);
}
Transition transition;
@@ -88,7 +88,7 @@ namespace Mistelix.Core
Logger.Debug ("SlideShow.Generate. Send Fixed image {0}, time {1} (frames)", i, (uint) (frames_sec * images[i].ShowTime));
transition = TransitionManager.CreateFromName (images[i].Transition);
- lib.SlideShowAddImageFixed (((SlideImage)images[i]), (uint) (frames_sec * images[i].ShowTime));
+ Backends.GStreamer.SlideShow.AddImageFixed (((SlideImage)images[i]), (uint) (frames_sec * images[i].ShowTime));
// Transition between two images
Logger.Debug ("SlideShow.Generate. Generate transition for frames_sec {0} and time {1}", frames_sec, images[i].TransitionTime);
@@ -100,14 +100,14 @@ namespace Mistelix.Core
transition.Target = (SlideImage) images[i + 1];
transition.Frames = frames_sec * images[i].TransitionTime;
foreach (SlideImage img in transition)
- lib.SlideShowAddImage (img);
+ Backends.GStreamer.SlideShow.AddImage (img);
Logger.Debug ("Sending subimage completed");
((SlideImage) images[i]).ReleasePixels ();
}
Logger.Debug ("SlideShow.Generate. Send fixed image time {0} (frames)", (uint) (frames_sec * images[images.Count -1].ShowTime));
- lib.SlideShowAddImageFixed (((SlideImage)images[images.Count - 1]), (uint) (frames_sec * images[images.Count -1].ShowTime));
+ Backends.GStreamer.SlideShow.AddImageFixed (((SlideImage)images[images.Count - 1]), (uint) (frames_sec * images[images.Count -1].ShowTime));
((SlideImage) images[images.Count - 1]).ReleasePixels ();
if (progress != null) {
@@ -116,7 +116,7 @@ namespace Mistelix.Core
}
// This a blocking call. It does not return until the pipeline sends an EOS
- lib.SlideShowClose ();
+ Backends.GStreamer.SlideShow.Close ();
Logger.Debug ("SlideShow.Generate. Finished generation");
return project.FileToFullPath (outfile);
}
diff --git a/src/Core/Video.cs b/src/Core/Video.cs
index 01680ca..e4b24cf 100644
--- a/src/Core/Video.cs
+++ b/src/Core/Video.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using Mistelix.Transitions;
using Mistelix.DataModel;
using Mistelix.Widgets;
+using Mistelix.Backends.GStreamer;
namespace Mistelix.Core
{
@@ -47,7 +48,7 @@ namespace Mistelix.Core
{
bool rslt;
- rslt = MistelixLib.IsMediaSupported (filename, out msg);
+ rslt = Backends.GStreamer.Video.IsSupported (filename, out msg);
Logger.Debug ("Video.SupportedFormat. Filename {0} is {1}", filename, rslt);
return rslt;
}
@@ -60,7 +61,7 @@ namespace Mistelix.Core
Logger.Debug ("Video.Convert. File {0} to {1}", filename, outfile);
// TODO: If rslt != 0 throw an exception
- rslt = MistelixLib.ConvertMedia (filename, outfile, (uint) project.Details.FramesPerSecond);
+ rslt = Backends.GStreamer.Video.Convert (filename, outfile, (uint) project.Details.FramesPerSecond);
return outfile;
}
}
diff --git a/src/DataModel/VideoProjectElement.cs b/src/DataModel/VideoProjectElement.cs
index 18314fd..746ecb7 100644
--- a/src/DataModel/VideoProjectElement.cs
+++ b/src/DataModel/VideoProjectElement.cs
@@ -28,11 +28,12 @@ using System.Xml.Serialization;
using Gdk;
using Mistelix.Core;
+using Mistelix.Backends.GStreamer;
namespace Mistelix.DataModel
{
// Describes a video within the authoring project
- [XmlInclude (typeof (Video))]
+ [XmlInclude (typeof (Core.Video))]
public class VideoProjectElement : VisibleProjectElement
{
public VideoProjectElement ()
@@ -62,7 +63,7 @@ namespace Mistelix.DataModel
public override Gdk.Pixbuf GetThumbnail (int width, int height)
{
Gdk.Pixbuf im;
- im = MistelixLib.VideoScreenshot (filename);
+ im = Backends.GStreamer.Thumbnail.VideoScreenshot (filename);
int max = Math.Max (im.Width, im.Height);
Gdk.Pixbuf scaled = im.ScaleSimple (width * im.Width / max, height * im.Height / max, InterpType.Nearest);
im.Dispose ();
diff --git a/src/Makefile.am b/src/Makefile.am
index 77ab465..71c4cb4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,7 +37,6 @@ MISTELIX_CSDISTFILES = \
$(srcdir)/Backends/Spumux.cs \
$(srcdir)/Backends/DvdAuthor.cs \
$(srcdir)/DataModel/Transition.cs \
- $(srcdir)/Core/MistelixLib.cs \
$(srcdir)/Core/NoneTransition.cs \
$(srcdir)/Core/TransitionManager.cs \
$(srcdir)/Core/XmlStorage.cs \
@@ -73,7 +72,12 @@ MISTELIX_CSDISTFILES = \
$(srcdir)/Widgets/CairoImageCellRenderer.cs \
$(srcdir)/Widgets/WelcomeView.cs \
$(srcdir)/DataModel/RecentFile.cs \
- $(srcdir)/Core/RecentFilesStorage.cs
+ $(srcdir)/Core/RecentFilesStorage.cs \
+ $(srcdir)/Backends/GStreamer/Video.cs \
+ $(srcdir)/Backends/GStreamer/Thumbnail.cs \
+ $(srcdir)/Backends/GStreamer/SlideShow.cs \
+ $(srcdir)/Backends/GStreamer/Plugins.cs \
+ $(srcdir)/Backends/OS/Unix.cs
ASSEMBLIES = \
$(MISTELIX_LIBS) \
diff --git a/src/Widgets/VideosFileView.cs b/src/Widgets/VideosFileView.cs
index da21dc7..16200c5 100644
--- a/src/Widgets/VideosFileView.cs
+++ b/src/Widgets/VideosFileView.cs
@@ -30,6 +30,7 @@ using Mistelix.DataModel;
using System.ComponentModel;
using Mistelix.Core;
+using Mistelix.Backends.GStreamer;
namespace Mistelix.Widgets
{
@@ -54,7 +55,7 @@ namespace Mistelix.Widgets
int pos;
filename = filename.ToLower ();
- extensions = MistelixLib.VideoExtensions ();
+ extensions = Backends.GStreamer.Video.FileExtensions ();
foreach (string extension in extensions) {
pos = extension.IndexOf ("."); // Extensions are returned as [*.ext]
@@ -78,7 +79,8 @@ namespace Mistelix.Widgets
try {
Gdk.Pixbuf im;
- im = MistelixLib.VideoScreenshot (file);
+ // TODO: This should be at VideoProjectElement.GetThumbnail
+ im = Backends.GStreamer.Thumbnail.VideoScreenshot (file);
int max = Math.Max (im.Width, im.Height);
Gdk.Pixbuf scaled = im.ScaleSimple (thumbnail_width * im.Width / max, thumbnail_height * im.Height / max, InterpType.Nearest);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]