#include "gstgdkanimation.h"
#include <gst/gstinfo.h>
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
typedef struct {
/* stuff gdk throws at us and we're supposed to keep */
g_free (context);
return NULL;
}
+ context->ani->temp_fd = g_file_open_tmp (NULL, &context->ani->temp_location, error);
+ if (context->ani->temp_fd == 0) {
+ g_object_unref (context->ani);
+ g_free (context);
+ return NULL;
+ }
+
GST_LOG_OBJECT (context->ani, "begin loading");
return context;
}
static GdkPixbufAnimation *
gst_loader_load_animation (FILE *f, GError **error)
{
- guchar data[4096];
- guint size;
- GdkPixbufAnimationIter *iter;
+ gchar *filename;
GstGdkAnimation *ani;
+ GdkPixbufAnimationIter *iter = NULL;
if (!gst_loader_init (error))
return NULL;
if (!ani)
return NULL;
- while ((size = fread (data, 1, 4096, f)) > 0) {
- if (!gst_gdk_animation_add_data (ani, data, size)) {
- g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
- "could not add more data to animation"); /* our errors suck ;) */
- g_object_unref (ani);
- GST_WARNING ("load_animation failed");
- return NULL;
- }
+ filename = g_strdup_printf ("/proc/self/fd/%d", fileno (f));
+ ani->temp_fd = open (filename, 0);
+ if (ani->temp_fd >= 0) {
+ iter = gdk_pixbuf_animation_get_iter (GDK_PIXBUF_ANIMATION (ani), NULL);
+ } else {
+ GST_DEBUG ("open (\"%s\", 0) failed", filename);
}
- gst_gdk_animation_done_adding (ani);
- iter = gdk_pixbuf_animation_get_iter (GDK_PIXBUF_ANIMATION (ani), NULL);
+ g_free (filename);
if (iter == NULL) {
- g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- "could not create an image");
- g_object_unref (ani);
- GST_INFO ("could not create an image");
- return NULL;
+ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ "could not create an image");
+ g_object_unref (ani);
+ GST_INFO ("could not create an image");
+ return NULL;
}
g_object_unref (iter);
GST_LOG_OBJECT (ani, "load_animation succeeded");
fill_info (GdkPixbufFormat *info)
{
static GdkPixbufModulePattern signature[] = {
+ /* AVI */
{ "RIFF AVI ", " xxxx ", 100 },
+ /* MPEG 1 */
{ "xx\001\272", "zz ", 100 },
+ /* Quicktime */
+ { " wide", "xxxx ", 80 },
+ { " moov", "xxxx ", 80 },
+ { " mdat", "xxxx ", 80 },
+ { " pnot", "xxxx ", 80 },
+ { " PICT", "xxxx ", 80 },
+ { " free", "xxxx ", 80 },
{ NULL, NULL, 0 }
};
static gchar *mime_types[] = {
- "video/avi",
+ "video/avi", "video/x-avi",
"video/mpeg",
NULL
};
static gchar *extensions[] = {
"avi",
"mpeg", "mpe", "mpg",
+ "mov",
NULL
};
{
GstGdkAnimation *ani = GST_GDK_ANIMATION (g_object_new (GST_TYPE_GDK_ANIMATION, NULL));
- ani->temp_fd = g_file_open_tmp (NULL, &ani->temp_location, error);
- if (ani->temp_fd == 0) {
- g_object_unref (ani);
- return NULL;
- }
-
return ani;
}
gboolean
gst_gdk_animation_get_static_image (GdkPixbufAnimation *animation)
{
GstGdkAnimation *ani = GST_GDK_ANIMATION (animation);
+ GTimeVal tv;
+ if (!ani->pixbuf) {
+ GST_LOG_OBJECT (ani, "trying to create pixbuf");
+ g_get_current_time (&tv);
+ GdkPixbufAnimationIter *iter = gdk_pixbuf_animation_get_iter (animation, &tv);
+ if (iter) {
+ guint64 length;
+ GstFormat time = GST_FORMAT_TIME;
+
+ if (!gst_element_query (gst_bin_get_by_name (GST_BIN (
+ GST_GDK_ANIMATION_ITER (iter)->pipeline), "sink"),
+ GST_QUERY_TOTAL, &time, &length)) {
+ length = 0;
+ }
+ if (length > 120 * GST_SECOND) {
+ length = 120 * GST_SECOND;
+ } else if (length < 120 * GST_SECOND && length >= 10 * GST_SECOND) {
+ length = length / 2;
+ }
+ g_assert (time == GST_FORMAT_TIME);
+ if (length > 0)
+ g_time_val_add (&tv, length * 1000 / GST_SECOND);
+ GST_LOG_OBJECT (ani, "using time offset %"G_GUINT64_FORMAT" for creating static image",
+ length);
+ gdk_pixbuf_animation_iter_advance (GDK_PIXBUF_ANIMATION_ITER (iter), &tv);
+ ani->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (iter);
+ g_object_ref (ani->pixbuf);
+ } else {
+ GST_DEBUG_OBJECT (ani, "Could not get an iterator. No pixbuf available");
+ }
+ }
return ani->pixbuf;
}
iter->buffers = g_queue_new ();
iter->eos = FALSE;
+ /* workaround for loads of demuxers that don't handle seeks before initializing... */
+ iter->just_seeked = TRUE;
}
static void
gst_gdk_animation_iter_finalize (GObject *object)
G_OBJECT_CLASS (iter_parent_class)->finalize (object);
}
static void
-got_handoff (GstElement *fakesink, GstBuffer *buffer, GstGdkAnimationIter *iter)
+got_handoff (GstElement *fakesink, GstBuffer *buffer, GstPad *pad, GstGdkAnimationIter *iter)
{
- GST_LOG_OBJECT (iter, "enqueing buffer %p", buffer);
+ GST_LOG_OBJECT (iter, "enqueing buffer %p (timestamp %"G_GUINT64_FORMAT")",
+ buffer, GST_BUFFER_TIMESTAMP (buffer));
gst_data_ref (GST_DATA (buffer));
g_queue_push_tail (iter->buffers, buffer);
}
-static GstElement *
+static gboolean
gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter *iter)
{
- GstElement *ret;
GstElement *src, *autoplugger, *sink, *colorspace;
GstCaps *caps = GST_CAPS_NEW ("pixbuf_filter",
"video/x-raw-rgb",
GST_PROPS_INT (32),
GST_PROPS_INT (24)
),
- "red_mask", GST_PROPS_INT (0x000000FF),
+ "red_mask", GST_PROPS_INT (0x00FF0000),
"green_mask", GST_PROPS_INT (0x0000FF00),
- "blue_mask", GST_PROPS_INT (0x00FF0000)
+ "blue_mask", GST_PROPS_INT (0x000000FF)
);
- ret = gst_element_factory_make ("pipeline", "main_pipeline");
- if (!ret) return NULL;
+ iter->pipeline = gst_element_factory_make ("pipeline", "main_pipeline");
+ if (iter->pipeline == NULL) return FALSE;
if (!(src = gst_element_factory_make ("filesrc", "source")))
goto error;
- gst_bin_add (GST_BIN (ret), src);
- g_object_set (src, "location", iter->ani->temp_location, NULL);
+ gst_bin_add (GST_BIN (iter->pipeline), src);
+ if (iter->ani->temp_location) {
+ g_object_set (src, "location", iter->ani->temp_location, NULL);
+ GST_INFO_OBJECT (iter, "using file '%s'", iter->ani->temp_location);
+ } else {
+ gchar *filename = g_strdup_printf ("/proc/self/fd/%d", iter->ani->temp_fd);
+ g_object_set (src, "location", filename, NULL);
+ GST_INFO_OBJECT (iter, "using file '%s'", filename);
+ g_free (filename);
+ }
if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
goto error;
- gst_bin_add (GST_BIN (ret), autoplugger);
+ gst_bin_add (GST_BIN (iter->pipeline), autoplugger);
if (!gst_element_link (src, autoplugger))
goto error;
+
+ /* add ffcolorspace if available so we get svq1, too */
+ if ((colorspace = gst_element_factory_make ("ffcolorspace", "ffcolorspace"))) {
+ gst_bin_add (GST_BIN (iter->pipeline), colorspace);
+ if (!gst_element_link (autoplugger, colorspace))
+ goto error;
+ autoplugger = colorspace;
+ }
+
if (!(colorspace = gst_element_factory_make ("colorspace", "colorspace")))
goto error;
- gst_bin_add (GST_BIN (ret), colorspace);
+ gst_bin_add (GST_BIN (iter->pipeline), colorspace);
if (!gst_element_link (autoplugger, colorspace))
goto error;
goto error;
g_object_set (sink, "signal-handoffs", TRUE, NULL);
g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
- gst_bin_add (GST_BIN (ret), sink);
+ gst_bin_add (GST_BIN (iter->pipeline), sink);
if (!gst_element_link_filtered (colorspace, sink, caps))
goto error;
- if (gst_element_set_state (ret, GST_STATE_PLAYING) != GST_STATE_SUCCESS)
+ if (gst_element_set_state (iter->pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS)
goto error;
- return ret;
+ return TRUE;
error:
- g_object_unref (ret);
- return NULL;
+ g_object_unref (iter->pipeline);
+ iter->pipeline = NULL;
+ return FALSE;
}
static gboolean
gst_gdk_animation_iter_may_advance (GstGdkAnimationIter *iter)
gint64 offset;
gint64 data_amount;
- if (iter->ani->temp_fd == 0)
+ if (iter->ani->temp_fd == 0 || iter->ani->temp_location == NULL)
return TRUE;
data_amount = lseek (iter->ani->temp_fd, 0, SEEK_CUR);
GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
GstGdkAnimationIter *iter;
- if (ani->temp_fd != 0 && lseek (ani->temp_fd, 0, SEEK_CUR) < GST_GDK_BUFFER_SIZE)
+ if (ani->temp_fd != 0 && ani->temp_location != NULL &&
+ lseek (ani->temp_fd, 0, SEEK_CUR) < GST_GDK_BUFFER_SIZE) {
+ GST_DEBUG_OBJECT (ani, "Not enough data to create iterator.");
return NULL;
-
+ }
+
iter = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
iter->start = *start_time;
iter->ani = ani;
g_object_ref (ani);
- iter->pipeline = gst_gdk_animation_iter_create_pipeline (iter);
- if (iter->pipeline == NULL)
+ if (!gst_gdk_animation_iter_create_pipeline (iter))
goto error;
-
if (!gst_gdk_animation_get_more_buffers (iter))
goto error;
gst_gdk_animation_iter_create_pixbuf (iter);
- if (!ani->pixbuf) {
- /* set our static image */
- g_object_ref (iter->pixbuf);
- ani->pixbuf = iter->pixbuf;
- }
return GDK_PIXBUF_ANIMATION_ITER (iter);
} else {
offset += ((GstClockTime) current_time->tv_usec - iter->start.tv_usec) * GST_SECOND / G_USEC_PER_SEC;
}
+ if (!iter->just_seeked &&
+ offset - iter->last_timestamp > GST_GDK_MAX_DELAY_TO_SEEK) {
+ GST_INFO_OBJECT (iter, "current pipeline timestamp is too old (%"G_GUINT64_FORMAT
+ " vs %"G_GUINT64_FORMAT"), seeking", iter->last_timestamp, offset);
+ if (gst_element_send_event (gst_bin_get_by_name (GST_BIN (iter->pipeline), "sink"),
+ gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
+ GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+ offset - GST_SECOND / 10))) {
+ iter->last_timestamp = offset - GST_SECOND / 10;
+ iter->just_seeked = TRUE;
+ } else {
+ GST_WARNING_OBJECT (iter, "seek to %"G_GUINT64_FORMAT" didn't work. Iterating there...",
+ offset);
+ }
+ } else if (iter->just_seeked) {
+ iter->just_seeked = FALSE;
+ }
while (TRUE) {
if (g_queue_is_empty (iter->buffers)) {
if (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) > offset)
break;
if (buffer) {
- GST_LOG_OBJECT (iter, "unreffing buffer %p, because timestamp too low (%"G_GUINT64_FORMAT" vs %"G_GUINT64_FORMAT")",
+ GST_LOG_OBJECT (iter, "unreffing buffer %p, because timestamp too low (%"
+ G_GUINT64_FORMAT" vs %"G_GUINT64_FORMAT")",
buffer, GST_BUFFER_TIMESTAMP (buffer), offset);
gst_data_unref (GST_DATA (buffer));
}
}
if (!buffer)
return FALSE;
+ if (GST_BUFFER_TIMESTAMP (buffer) < iter->last_timestamp) {
+ gst_data_unref (GST_DATA (buffer));
+ iter->last_timestamp = offset;
+ return FALSE;
+ }
iter->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
g_queue_push_head (iter->buffers, buffer);
gst_gdk_animation_iter_create_pixbuf (iter);