Printf format fixes.
[platform/upstream/gst-plugins-good.git] / ext / gdk_pixbuf / gstgdkanimation.c
1 /*
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstgdkanimation.h"
25 #include <unistd.h>
26
27 GST_DEBUG_CATEGORY_STATIC (gst_gdk_animation_debug);
28 #define GST_CAT_DEFAULT gst_gdk_animation_debug
29
30 static void gst_gdk_animation_class_init (gpointer g_class,
31     gpointer class_data);
32 static void gst_gdk_animation_finalize (GObject * object);
33
34 static gboolean gst_gdk_animation_is_static_image (GdkPixbufAnimation *
35     animation);
36 static GdkPixbuf *gst_gdk_animation_get_static_image (GdkPixbufAnimation *
37     animation);
38 static void gst_gdk_animation_get_size (GdkPixbufAnimation * anim, gint * width,
39     gint * height);
40 static GdkPixbufAnimationIter *gst_gdk_animation_get_iter (GdkPixbufAnimation *
41     anim, const GTimeVal * start_time);
42
43
44 static gpointer parent_class;
45
46 GType
47 gst_gdk_animation_get_type (void)
48 {
49   static GType object_type = 0;
50
51   if (!object_type) {
52     static const GTypeInfo object_info = {
53       sizeof (GstGdkAnimationClass),
54       NULL,
55       NULL,
56       gst_gdk_animation_class_init,
57       NULL,                     /* class_finalize */
58       NULL,                     /* class_data */
59       sizeof (GstGdkAnimation),
60       0,                        /* n_preallocs */
61       NULL,
62     };
63
64     object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
65         "GstGdkAnimation", &object_info, 0);
66
67     GST_DEBUG_CATEGORY_INIT (gst_gdk_animation_debug, "gstloader_animation", 0,
68         "GStreamer GdkPixbuf loader - GdkAnimation class");
69   }
70
71   return object_type;
72 }
73 static void
74 gst_gdk_animation_class_init (gpointer g_class, gpointer class_data)
75 {
76   GObjectClass *object_class = G_OBJECT_CLASS (g_class);
77   GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (g_class);
78
79   parent_class = g_type_class_peek_parent (g_class);
80
81   object_class->finalize = gst_gdk_animation_finalize;
82
83   anim_class->is_static_image = gst_gdk_animation_is_static_image;
84   anim_class->get_static_image = gst_gdk_animation_get_static_image;
85   anim_class->get_size = gst_gdk_animation_get_size;
86   anim_class->get_iter = gst_gdk_animation_get_iter;
87 }
88 static void
89 gst_gdk_animation_finalize (GObject * object)
90 {
91   GstGdkAnimation *ani = GST_GDK_ANIMATION (object);
92
93   if (ani->temp_fd) {
94     close (ani->temp_fd);
95   }
96   if (ani->temp_location) {
97     remove (ani->temp_location);
98     g_free (ani->temp_location);
99   }
100   if (ani->pixbuf) {
101     g_object_unref (ani->pixbuf);
102     ani->pixbuf = NULL;
103   }
104
105   G_OBJECT_CLASS (parent_class)->finalize (object);
106 }
107
108 GstGdkAnimation *
109 gst_gdk_animation_new (GError ** error)
110 {
111   GstGdkAnimation *ani =
112       GST_GDK_ANIMATION (g_object_new (GST_TYPE_GDK_ANIMATION, NULL));
113
114   return ani;
115 }
116
117 gboolean
118 gst_gdk_animation_add_data (GstGdkAnimation * ani, const guint8 * data,
119     guint size)
120 {
121   return (write (ani->temp_fd, data, size) == size);
122 }
123
124 void
125 gst_gdk_animation_done_adding (GstGdkAnimation * ani)
126 {
127   close (ani->temp_fd);
128   ani->temp_fd = 0;
129 }
130
131 static gboolean
132 gst_gdk_animation_is_static_image (GdkPixbufAnimation * animation)
133 {
134   return FALSE;
135 }
136
137 static void
138 gst_gdk_animation_get_size (GdkPixbufAnimation * anim, gint * width,
139     int *height)
140 {
141   GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
142
143   GST_LOG_OBJECT (ani, "get_size called (%p, %p) %d x %d", width, height,
144       ani->width, ani->height);
145   if (width)
146     *width = ani->width;
147
148   if (height)
149     *height = ani->height;
150 }
151
152
153 static void gst_gdk_animation_iter_class_init (gpointer g_class,
154     gpointer class_data);
155 static void gst_gdk_animation_iter_init (GTypeInstance * instance,
156     gpointer g_class);
157 static void gst_gdk_animation_iter_finalize (GObject * object);
158
159 static gint gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter *
160     iter);
161 static GdkPixbuf *gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter *
162     iter);
163 static gboolean
164 gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *
165     iter);
166 static gboolean gst_gdk_animation_iter_advance (GdkPixbufAnimationIter * iter,
167     const GTimeVal * current_time);
168
169 static gpointer iter_parent_class;
170
171 GType
172 gst_gdk_animation_iter_get_type (void)
173 {
174   static GType object_type = 0;
175
176   if (!object_type) {
177     static const GTypeInfo object_info = {
178       sizeof (GstGdkAnimationIterClass),
179       NULL,
180       NULL,
181       gst_gdk_animation_iter_class_init,
182       NULL,                     /* class_finalize */
183       NULL,                     /* class_data */
184       sizeof (GstGdkAnimationIter),
185       0,                        /* n_preallocs */
186       gst_gdk_animation_iter_init,
187     };
188
189     object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
190         "GdkPixbufAniAnimIter", &object_info, 0);
191   }
192
193   return object_type;
194 }
195
196 static void
197 gst_gdk_animation_iter_class_init (gpointer g_class, gpointer class_data)
198 {
199   GObjectClass *object_class = G_OBJECT_CLASS (g_class);
200   GdkPixbufAnimationIterClass *anim_iter_class =
201       GDK_PIXBUF_ANIMATION_ITER_CLASS (g_class);
202
203   iter_parent_class = g_type_class_peek_parent (g_class);
204
205   object_class->finalize = gst_gdk_animation_iter_finalize;
206
207   anim_iter_class->get_delay_time = gst_gdk_animation_iter_get_delay_time;
208   anim_iter_class->get_pixbuf = gst_gdk_animation_iter_get_pixbuf;
209   anim_iter_class->on_currently_loading_frame =
210       gst_gdk_animation_iter_on_currently_loading_frame;
211   anim_iter_class->advance = gst_gdk_animation_iter_advance;
212 }
213 static void
214 gst_gdk_animation_iter_init (GTypeInstance * instance, gpointer g_class)
215 {
216   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (instance);
217
218   iter->buffers = g_queue_new ();
219   iter->eos = FALSE;
220 }
221 static void
222 gst_gdk_animation_iter_finalize (GObject * object)
223 {
224   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (object);
225
226   g_object_unref (iter->ani);
227
228   if (iter->pipeline)
229     g_object_unref (iter->pipeline);
230   if (iter->pixbuf)
231     g_object_unref (iter->pixbuf);
232   while (iter->buffers) {
233     GstBuffer *buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
234
235     if (buffer) {
236       GST_LOG_OBJECT (iter, "unreffing buffer %p on finalize", buffer);
237       gst_data_unref (GST_DATA (buffer));
238     } else {
239       g_queue_free (iter->buffers);
240       iter->buffers = NULL;
241     }
242   }
243   G_OBJECT_CLASS (iter_parent_class)->finalize (object);
244 }
245 static void
246 got_handoff (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
247     GstGdkAnimationIter * iter)
248 {
249   GST_LOG_OBJECT (iter, "enqueing buffer %p (timestamp %" G_GUINT64_FORMAT ")",
250       buffer, GST_BUFFER_TIMESTAMP (buffer));
251   gst_data_ref (GST_DATA (buffer));
252   g_queue_push_tail (iter->buffers, buffer);
253 }
254
255 static gboolean
256 gst_gdk_animation_iter_create_pipeline (GstGdkAnimationIter * iter)
257 {
258   GstElement *src, *typefind, *autoplugger, *sink, *colorspace;
259   GstCaps *caps = GST_CAPS_NEW ("pixbuf_filter32",
260       "video/x-raw-rgb",
261       "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
262       "bpp", GST_PROPS_INT (32),
263       "red_mask", GST_PROPS_INT (0xFF000000),
264       "green_mask", GST_PROPS_INT (0x00FF0000),
265       "blue_mask", GST_PROPS_INT (0x0000FF00)
266       );
267
268   gst_caps_append (caps, GST_CAPS_NEW ("pixbuf_filter24",
269           "video/x-raw-rgb",
270           "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
271           "bpp", GST_PROPS_INT (24),
272           "red_mask", GST_PROPS_INT (0xFF0000),
273           "green_mask", GST_PROPS_INT (0x00FF00),
274           "blue_mask", GST_PROPS_INT (0x0000FF)
275       ));
276
277   iter->pipeline = gst_element_factory_make ("pipeline", "main_pipeline");
278   if (iter->pipeline == NULL)
279     return FALSE;
280
281   if (!(src = gst_element_factory_make ("filesrc", "source")))
282     goto error;
283   gst_bin_add (GST_BIN (iter->pipeline), src);
284   if (iter->ani->temp_location) {
285     g_object_set (src, "location", iter->ani->temp_location, NULL);
286     GST_INFO_OBJECT (iter, "using file '%s'", iter->ani->temp_location);
287   } else {
288     gchar *filename = g_strdup_printf ("/proc/self/fd/%d", iter->ani->temp_fd);
289
290     g_object_set (src, "location", filename, NULL);
291     GST_INFO_OBJECT (iter, "using file '%s'", filename);
292     g_free (filename);
293   }
294
295   /* add typefind for correct typefinding */
296   if ((typefind = gst_element_factory_make ("typefind", "typefind"))) {
297     gst_bin_add (GST_BIN (iter->pipeline), typefind);
298     if (!gst_element_link (src, typefind))
299       goto error;
300   }
301
302   if (!(autoplugger = gst_element_factory_make ("spider", "autoplugger")))
303     goto error;
304   gst_bin_add (GST_BIN (iter->pipeline), autoplugger);
305   if (!gst_element_link (typefind, autoplugger))
306     goto error;
307
308   /* try ffcolorspace if available so we get svq1, too */
309   colorspace = gst_element_factory_make ("ffcolorspace", "ffcolorspace");
310   if (!colorspace)
311     colorspace = gst_element_factory_make ("colorspace", "colorspace");
312   if (!colorspace)
313     goto error;
314   gst_bin_add (GST_BIN (iter->pipeline), colorspace);
315   if (!gst_element_link (autoplugger, colorspace))
316     goto error;
317
318   if (!(sink = gst_element_factory_make ("fakesink", "sink")))
319     goto error;
320   g_object_set (sink, "signal-handoffs", TRUE, NULL);
321   g_signal_connect (sink, "handoff", (GCallback) got_handoff, iter);
322   gst_bin_add (GST_BIN (iter->pipeline), sink);
323   if (!gst_element_link_filtered (colorspace, sink, caps))
324     goto error;
325   if (gst_element_set_state (iter->pipeline,
326           GST_STATE_PLAYING) != GST_STATE_CHANGE_SUCCESS)
327     goto error;
328
329   return TRUE;
330 error:
331   g_object_unref (iter->pipeline);
332   iter->pipeline = NULL;
333   return FALSE;
334 }
335
336 static gboolean
337 gst_gdk_animation_iter_may_advance (GstGdkAnimationIter * iter)
338 {
339   GstFormat bytes = GST_FORMAT_BYTES;
340   gint64 offset;
341   gint64 data_amount;
342
343   if (iter->ani->temp_fd == 0 || iter->ani->temp_location == NULL)
344     return TRUE;
345
346   data_amount = lseek (iter->ani->temp_fd, 0, SEEK_CUR);
347   g_assert (data_amount >= 0);
348   if (!gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline),
349               "source"), GST_QUERY_POSITION, &bytes, &offset))
350     g_assert_not_reached ();
351   if (data_amount - offset > GST_GDK_BUFFER_SIZE)
352     return TRUE;
353
354   return FALSE;
355 }
356
357 static gboolean
358 gst_gdk_animation_get_more_buffers (GstGdkAnimationIter * iter)
359 {
360   GstBuffer *last = g_queue_peek_tail (iter->buffers);
361
362   do {
363     GST_LOG_OBJECT (iter, "iterating...");
364     if (!gst_gdk_animation_iter_may_advance (iter)) {
365       GST_LOG_OBJECT (iter, "no more data available");
366       break;
367     }
368     if (!gst_bin_iterate (GST_BIN (iter->pipeline))) {
369       GST_LOG_OBJECT (iter, "iterating done, setting EOS");
370       iter->eos = TRUE;
371       break;
372     }
373   } while (last == g_queue_peek_tail (iter->buffers));
374   return last != g_queue_peek_tail (iter->buffers);
375 }
376 static void
377 pixbuf_destroy_notify (guchar * pixels, gpointer data)
378 {
379   GST_LOG ("unreffing buffer %p because pixbuf was destroyed", data);
380   gst_data_unref (GST_DATA (data));
381 }
382 static void
383 gst_gdk_animation_iter_create_pixbuf (GstGdkAnimationIter * iter)
384 {
385   GstBuffer *buf;
386   GstGdkAnimation *ani = iter->ani;
387
388   buf = g_queue_pop_head (iter->buffers);
389   g_assert (buf);
390   if (iter->pixbuf) {
391     GST_LOG_OBJECT (iter, "unreffing pixbuf %p", iter->pixbuf);
392     g_object_unref (iter->pixbuf);
393   }
394   if (ani->width == 0) {
395     GstPad *pad;
396     GstCaps *caps;
397     GstElement *fakesink =
398         gst_bin_get_by_name (GST_BIN (iter->pipeline), "sink");
399     g_assert (fakesink);
400     pad = gst_element_get_pad (fakesink, "sink");
401     g_assert (pad);
402     caps = gst_pad_get_negotiated_caps (pad);
403     g_assert (caps);
404     g_assert (GST_CAPS_IS_FIXED (caps));
405     g_assert (gst_caps_has_fixed_property (caps, "bpp") &&
406         gst_caps_has_fixed_property (caps, "width") &&
407         gst_caps_has_fixed_property (caps, "height"));
408     gst_caps_get_int (caps, "width", &ani->width);
409     gst_caps_get_int (caps, "height", &ani->height);
410     gst_caps_get_int (caps, "bpp", &ani->bpp);
411     GST_DEBUG_OBJECT (ani, "found format (width %d, height %d, bpp %d)",
412         ani->width, ani->height, ani->bpp);
413   }
414   g_assert (GST_BUFFER_SIZE (buf) == ani->width * ani->height * ani->bpp / 8);
415   if (ani->bpp == 32) {
416     gint i;
417     guint32 *data = (guint32 *) GST_BUFFER_DATA (buf);
418
419     /* ensure opacity */
420     for (i = 0; i < ani->width * ani->height; i++) {
421       data[i] |= 0xFF000000;
422     }
423   }
424   iter->pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf),
425       GDK_COLORSPACE_RGB, ani->bpp == 32, 8, ani->width, ani->height,
426       ani->width * ani->bpp / 8, pixbuf_destroy_notify, buf);
427   GST_LOG_OBJECT (iter, "created pixbuf %p from buffer %p (refcount %d)",
428       iter->pixbuf, buf, GST_DATA_REFCOUNT_VALUE (buf));
429 }
430 static GdkPixbufAnimationIter *
431 gst_gdk_animation_get_iter (GdkPixbufAnimation * anim,
432     const GTimeVal * start_time)
433 {
434   GstGdkAnimation *ani = GST_GDK_ANIMATION (anim);
435   GstGdkAnimationIter *iter;
436
437   if (ani->temp_fd != 0 && ani->temp_location != NULL &&
438       lseek (ani->temp_fd, 0, SEEK_CUR) < GST_GDK_BUFFER_SIZE) {
439     GST_DEBUG_OBJECT (ani, "Not enough data to create iterator.");
440     return NULL;
441   }
442
443   iter = g_object_new (GST_TYPE_GDK_ANIMATION_ITER, NULL);
444
445   iter->start = *start_time;
446
447   iter->ani = ani;
448   g_object_ref (ani);
449   if (!gst_gdk_animation_iter_create_pipeline (iter))
450     goto error;
451
452   if (!gst_gdk_animation_get_more_buffers (iter))
453     goto error;
454
455   gst_gdk_animation_iter_create_pixbuf (iter);
456
457   return GDK_PIXBUF_ANIMATION_ITER (iter);
458
459 error:
460   g_object_unref (iter);
461   return NULL;
462 }
463
464 static gboolean
465 gst_gdk_animation_iter_advance (GdkPixbufAnimationIter * anim_iter,
466     const GTimeVal * current_time)
467 {
468   GstClockTime offset;
469   GstBuffer *buffer = NULL;
470   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
471
472   /* compute timestamp that next buffer must match */
473   offset =
474       ((GstClockTime) current_time->tv_sec - iter->start.tv_sec) * GST_SECOND;
475   if (iter->start.tv_usec > current_time->tv_usec) {
476     offset -=
477         ((GstClockTime) iter->start.tv_usec -
478         current_time->tv_usec) * GST_SECOND / G_USEC_PER_SEC;
479   } else {
480     offset +=
481         ((GstClockTime) current_time->tv_usec -
482         iter->start.tv_usec) * GST_SECOND / G_USEC_PER_SEC;
483   }
484   GST_DEBUG_OBJECT (iter,
485       "advancing to %ld:%ld (started at %ld:%ld) need offset %"
486       G_GUINT64_FORMAT, current_time->tv_sec, current_time->tv_usec,
487       iter->start.tv_sec, iter->start.tv_usec, offset);
488   if (!iter->just_seeked
489       && offset - iter->last_timestamp > GST_GDK_MAX_DELAY_TO_SEEK) {
490     GST_INFO_OBJECT (iter,
491         "current pipeline timestamp is too old (%" G_GUINT64_FORMAT " vs %"
492         G_GUINT64_FORMAT "), seeking there", iter->last_timestamp, offset);
493     if (gst_element_send_event (gst_bin_get_by_name (GST_BIN (iter->pipeline),
494                 "sink"),
495             gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
496                 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, offset))) {
497       iter->last_timestamp = offset;
498       iter->just_seeked = TRUE;
499     } else {
500       GST_WARNING_OBJECT (iter,
501           "seek to %" G_GUINT64_FORMAT " didn't work. Iterating there...",
502           offset);
503     }
504   } else if (iter->just_seeked) {
505     iter->just_seeked = FALSE;
506   }
507
508   while (TRUE) {
509     if (g_queue_is_empty (iter->buffers)) {
510       if (iter->eos)
511         return FALSE;
512       if (gst_gdk_animation_get_more_buffers (iter))
513         continue;
514       break;
515     }
516     if (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) > offset)
517       break;
518     if (buffer) {
519       GST_LOG_OBJECT (iter, "unreffing buffer %p, because timestamp too low (%"
520           G_GUINT64_FORMAT " vs %" G_GUINT64_FORMAT ")",
521           buffer, GST_BUFFER_TIMESTAMP (buffer), offset);
522       gst_data_unref (GST_DATA (buffer));
523     }
524     buffer = GST_BUFFER (g_queue_pop_head (iter->buffers));
525   }
526   if (!buffer)
527     return FALSE;
528   if (GST_BUFFER_TIMESTAMP (buffer) < iter->last_timestamp) {
529     gst_data_unref (GST_DATA (buffer));
530     iter->last_timestamp = offset;
531     return FALSE;
532   }
533   iter->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
534   g_queue_push_head (iter->buffers, buffer);
535   gst_gdk_animation_iter_create_pixbuf (iter);
536   return TRUE;
537 }
538
539 static gint
540 gst_gdk_animation_iter_get_delay_time (GdkPixbufAnimationIter * anim_iter)
541 {
542   gint delay;
543   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
544
545   while (g_queue_is_empty (iter->buffers)) {
546     if (iter->eos) {
547       GST_LOG_OBJECT (iter, "returning delay of infinite, we're EOS");
548       return -1;
549     }
550     if (!gst_gdk_animation_get_more_buffers (iter))
551       return -1;                /* FIXME? */
552   }
553
554   delay =
555       (GST_BUFFER_TIMESTAMP (g_queue_peek_head (iter->buffers)) -
556       iter->last_timestamp) * 1000 / GST_SECOND;
557   GST_LOG_OBJECT (iter, "returning delay of %d ms", delay);
558   return delay;
559 }
560
561 GdkPixbuf *
562 gst_gdk_animation_iter_get_pixbuf (GdkPixbufAnimationIter * anim_iter)
563 {
564   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
565
566   GST_LOG_OBJECT (iter, "returning pixbuf %p", iter->pixbuf);
567   return iter->pixbuf;
568 }
569
570 static gboolean
571 gst_gdk_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *
572     anim_iter)
573 {
574   GstGdkAnimationIter *iter = GST_GDK_ANIMATION_ITER (anim_iter);
575
576   /* EOS - last frame */
577   if (iter->eos && g_queue_is_empty (iter->buffers))
578     return TRUE;
579
580   /* can't load more frames */
581   if (!gst_gdk_animation_iter_may_advance (iter))
582     return FALSE;
583
584   return TRUE;
585 }
586 static GdkPixbuf *
587 gst_gdk_animation_get_static_image (GdkPixbufAnimation * animation)
588 {
589   GstGdkAnimation *ani = GST_GDK_ANIMATION (animation);
590   GTimeVal tv;
591   GstGdkAnimationIter *iter;
592
593   if (!ani->pixbuf) {
594     GST_LOG_OBJECT (ani, "trying to create pixbuf");
595     g_get_current_time (&tv);
596     iter =
597         GST_GDK_ANIMATION_ITER (gdk_pixbuf_animation_get_iter (animation, &tv));
598     if (iter) {
599       guint64 offset;
600       GstBuffer *buf;
601       GstFormat time = GST_FORMAT_TIME;
602
603       if (!gst_element_query (gst_bin_get_by_name (GST_BIN (iter->pipeline),
604                   "sink"), GST_QUERY_TOTAL, &time, &offset)) {
605         offset = 0;
606       }
607       if (offset > 120 * GST_SECOND) {
608         offset = 120 * GST_SECOND;
609       } else if (offset < 120 * GST_SECOND && offset >= 10 * GST_SECOND) {
610         offset = offset / 2;
611       }
612       g_assert (time == GST_FORMAT_TIME);
613       GST_LOG_OBJECT (ani,
614           "using time offset %" G_GUINT64_FORMAT " for creating static image",
615           offset);
616       while ((buf = g_queue_pop_head (iter->buffers)) != NULL) {
617         gst_data_unref (GST_DATA (buf));
618       }
619       /* now we do evil stuff, be sure to get rid of the iterator afterwards */
620       if (!gst_element_send_event (gst_bin_get_by_name (GST_BIN (iter->
621                       pipeline), "sink"),
622               gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
623                   GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, offset))) {
624         GST_INFO_OBJECT (ani, "seeking didn't work. Using next image");
625       }
626
627       do {
628         if (g_queue_is_empty (iter->buffers)) {
629           if (iter->eos)
630             return FALSE;
631           if (gst_gdk_animation_get_more_buffers (iter))
632             continue;
633         }
634       } while (FALSE);
635       if (!g_queue_is_empty (iter->buffers)) {
636         gst_gdk_animation_iter_create_pixbuf (iter);
637         ani->pixbuf =
638             gst_gdk_animation_iter_get_pixbuf (GDK_PIXBUF_ANIMATION_ITER
639             (iter));
640         g_object_ref (ani->pixbuf);
641       } else {
642         g_assert (ani->pixbuf == NULL);
643       }
644       /* DiE iterator, DiE */
645       g_object_unref (iter);
646     } else {
647       GST_DEBUG_OBJECT (ani, "Could not get an iterator. No pixbuf available");
648     }
649   }
650   GST_LOG_OBJECT (ani, "Returning pixbuf %p\n", ani->pixbuf);
651   return ani->pixbuf;
652 }