Skip to content

Commit fa982d6

Browse files
committed
Animation structure manipulation functions and modifications to existing functions to fit in with GdkPixbufAnimation.
1 parent 0e1a187 commit fa982d6

File tree

1 file changed

+203
-48
lines changed

1 file changed

+203
-48
lines changed

contrib/gdk-pixbuf/loader.c

Lines changed: 203 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ G_DECLARE_FINAL_TYPE(AvifAnimationIter, avif_animation_iter, GDK, AVIF_ANIMATION
5050

5151
G_DEFINE_TYPE(AvifAnimationIter, avif_animation_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
5252

53+
/* Animation class functions */
54+
static void avif_animation_finalize(GObject * obj)
5355
{
56+
AvifAnimation * context = (AvifAnimation *)obj;
5457
if (!context)
5558
return;
5659

@@ -69,57 +72,153 @@ G_DEFINE_TYPE(AvifAnimationIter, avif_animation_iter, GDK_TYPE_PIXBUF_ANIMATION_
6972
context->bytes = NULL;
7073
}
7174

72-
if (context->pixbuf) {
73-
g_object_unref(context->pixbuf);
74-
context->pixbuf = NULL;
75+
if (context->frames) {
76+
for(size_t i = 0; i < context->frames->len; i++){
77+
g_object_unref(g_array_index(context->frames, AvifAnimationFrame, i).pixbuf);
78+
}
79+
g_array_free(context->frames, TRUE);
7580
}
81+
}
7682

77-
g_free(context);
83+
static gboolean avif_animation_is_static_image(GdkPixbufAnimation * animation)
84+
{
85+
AvifAnimation * context = (AvifAnimation *)animation;
86+
return context->frames->len == 1;
7887
}
7988

80-
static gboolean avif_context_try_load(struct avif_context * context, GError ** error)
89+
static GdkPixbuf * avif_animation_get_static_image(GdkPixbufAnimation * animation)
8190
{
82-
avifResult ret;
83-
avifDecoder * decoder = context->decoder;
84-
avifImage * image;
85-
avifRGBImage rgb;
86-
const uint8_t * data;
87-
size_t size;
88-
int width, height;
89-
GdkPixbuf *output;
91+
AvifAnimation * context = (AvifAnimation *)animation;
92+
return g_array_index(context->frames, AvifAnimationFrame, 0).pixbuf;
93+
}
9094

91-
data = g_bytes_get_data(context->bytes, &size);
95+
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
96+
static GdkPixbufAnimationIter * avif_animation_get_iter(GdkPixbufAnimation * animation, const GTimeVal * start_time)
97+
{
98+
AvifAnimationIter * iter = g_object_new(GDK_TYPE_AVIF_ANIMATION_ITER, NULL);
9299

93-
ret = avifDecoderSetIOMemory(decoder, data, size);
94-
if (ret != AVIF_RESULT_OK) {
95-
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
96-
"Couldn't decode image: %s", avifResultToString(ret));
97-
return FALSE;
98-
}
100+
iter->animation = (AvifAnimation *)animation;
101+
g_object_ref(iter->animation);
99102

100-
ret = avifDecoderParse(decoder);
101-
if (ret != AVIF_RESULT_OK) {
102-
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
103-
"Couldn't decode image: %s", avifResultToString(ret));
104-
return FALSE;
105-
}
103+
iter->time_offset = start_time->tv_sec * 1000 + start_time->tv_usec / 1000;
104+
iter->current_frame = 0;
106105

107-
if (decoder->imageCount > 1) {
108-
g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
109-
"Image sequences not yet implemented");
110-
return FALSE;
106+
return (GdkPixbufAnimationIter *)iter;
107+
}
108+
G_GNUC_END_IGNORE_DEPRECATIONS
109+
110+
static void avif_animation_get_size(GdkPixbufAnimation * animation, int * width, int * height)
111+
{
112+
AvifAnimation * context = (AvifAnimation *)animation;
113+
if(width){
114+
*width = context->decoder->image->width;
115+
}
116+
if(height){
117+
*height = context->decoder->image->height;
111118
}
119+
}
112120

113-
ret = avifDecoderNextImage(decoder);
114-
if (ret == AVIF_RESULT_NO_IMAGES_REMAINING) {
115-
/* No more images, bail out. Verify that you got the expected amount of images decoded. */
116-
return TRUE;
117-
} else if (ret != AVIF_RESULT_OK) {
118-
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
119-
"Failed to decode all frames: %s", avifResultToString(ret));
120-
return FALSE;
121+
static void avif_animation_init(AvifAnimation * obj) {
122+
/* To ignore unused function and unused paremeter warnings/errors */
123+
(void)obj;
124+
}
125+
static void avif_animation_class_init(AvifAnimationClass * class) {
126+
class->parent_class.get_iter = avif_animation_get_iter;
127+
class->parent_class.get_size = avif_animation_get_size;
128+
class->parent_class.get_static_image = avif_animation_get_static_image;
129+
class->parent_class.is_static_image = avif_animation_is_static_image;
130+
G_OBJECT_CLASS(class)->finalize = avif_animation_finalize;
131+
}
132+
133+
/* Iterator class functions */
134+
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
135+
static gboolean avif_animation_iter_advance(GdkPixbufAnimationIter * iter, const GTimeVal * current_time)
136+
{
137+
AvifAnimationIter * avif_iter = (AvifAnimationIter *)iter;
138+
AvifAnimation * context = (AvifAnimation *)avif_iter->animation;
139+
140+
size_t prev_frame = avif_iter->current_frame;
141+
uint64_t elapsed_time = current_time->tv_sec * 1000 + current_time->tv_usec / 1000 - avif_iter->time_offset;
142+
143+
/*
144+
* duration in seconds stored in a double which is cast to uint64_t
145+
* is the precision loss here significant?
146+
* */
147+
uint64_t animation_time = (uint64_t)(context->decoder->duration * 1000);
148+
149+
if (context->decoder->repetitionCount > 0 && elapsed_time > animation_time * context->decoder->repetitionCount) {
150+
avif_iter->current_frame = context->decoder->imageCount - 1;
151+
} else {
152+
elapsed_time = elapsed_time % animation_time;
153+
154+
avif_iter->current_frame = 0;
155+
uint64_t frame_duration;
156+
157+
while (1) {
158+
frame_duration = g_array_index(context->frames, AvifAnimationFrame, avif_iter->current_frame).duration_ms;
159+
160+
if (elapsed_time <= frame_duration) {
161+
break;
162+
}
163+
elapsed_time -= frame_duration;
164+
avif_iter->current_frame++;
165+
}
121166
}
122167

168+
return prev_frame != avif_iter->current_frame;
169+
}
170+
G_GNUC_END_IGNORE_DEPRECATIONS
171+
172+
static int avif_animation_iter_get_delay_time(GdkPixbufAnimationIter * iter)
173+
{
174+
AvifAnimationIter * avif_iter = (AvifAnimationIter *)iter;
175+
return g_array_index(avif_iter->animation->frames, AvifAnimationFrame, avif_iter->current_frame).duration_ms;
176+
}
177+
178+
static GdkPixbuf * avif_animation_iter_get_pixbuf(GdkPixbufAnimationIter * iter)
179+
{
180+
AvifAnimationIter * avif_iter = (AvifAnimationIter *)iter;
181+
return g_array_index(avif_iter->animation->frames, AvifAnimationFrame, avif_iter->current_frame).pixbuf;
182+
}
183+
184+
static gboolean avif_animation_iter_on_currently_loading_frame(GdkPixbufAnimationIter * iter)
185+
{
186+
/* this function is effectively useless with how the rest of this module was written */
187+
(void)iter;
188+
return FALSE;
189+
}
190+
191+
static void avif_animation_iter_finalize(GObject * obj)
192+
{
193+
AvifAnimationIter * iter = (AvifAnimationIter *)obj;
194+
g_object_unref(iter->animation);
195+
g_object_unref(iter);
196+
}
197+
198+
199+
static void avif_animation_iter_init(AvifAnimationIter * obj) {
200+
/* To ignore unused function and unused paremeter warnings/errors */
201+
(void)obj;
202+
}
203+
static void avif_animation_iter_class_init(AvifAnimationIterClass * class) {
204+
class->parent_class.advance = avif_animation_iter_advance;
205+
class->parent_class.get_delay_time = avif_animation_iter_get_delay_time;
206+
class->parent_class.get_pixbuf = avif_animation_iter_get_pixbuf;
207+
class->parent_class.on_currently_loading_frame = avif_animation_iter_on_currently_loading_frame;
208+
G_OBJECT_CLASS(class)->finalize = avif_animation_iter_finalize;
209+
}
210+
211+
G_END_DECLS
212+
213+
GdkPixbuf* set_pixbuf(AvifAnimation * context, GError ** error)
214+
{
215+
avifResult ret;
216+
avifDecoder * decoder = context->decoder;
217+
GdkPixbuf * output;
218+
219+
avifImage * image;
220+
avifRGBImage rgb;
221+
int width, height;
123222
image = decoder->image;
124223
width = image->width;
125224
height = image->height;
@@ -282,14 +381,70 @@ static gboolean avif_context_try_load(struct avif_context * context, GError ** e
282381
g_free(icc_base64);
283382
}
284383

285-
if (context->pixbuf) {
286-
g_object_unref(context->pixbuf);
287-
context->pixbuf = NULL;
384+
return output;
385+
}
386+
387+
static gboolean avif_context_try_load(AvifAnimation * context, GError ** error)
388+
{
389+
390+
context->frames = g_array_new(FALSE, TRUE, sizeof(AvifAnimationFrame));
391+
392+
avifResult ret;
393+
avifDecoder * decoder = context->decoder;
394+
const uint8_t * data;
395+
size_t size;
396+
397+
data = g_bytes_get_data(context->bytes, &size);
398+
399+
ret = avifDecoderSetIOMemory(decoder, data, size);
400+
if (ret != AVIF_RESULT_OK) {
401+
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
402+
"Couldn't decode image: %s", avifResultToString(ret));
403+
return FALSE;
404+
}
405+
406+
ret = avifDecoderParse(decoder);
407+
if (ret != AVIF_RESULT_OK) {
408+
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
409+
"Couldn't decode image: %s", avifResultToString(ret));
410+
return FALSE;
411+
}
412+
413+
ret = avifDecoderNextImage(decoder);
414+
if (ret == AVIF_RESULT_NO_IMAGES_REMAINING) {
415+
/* No more images, bail out. Verify that you got the expected amount of images decoded. */
416+
return TRUE;
417+
} else if (ret != AVIF_RESULT_OK) {
418+
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
419+
"Failed to decode all frames: %s", avifResultToString(ret));
420+
return FALSE;
288421
}
289422

290-
context->pixbuf = output;
291-
context->prepared_func(context->pixbuf, NULL, context->user_data);
423+
AvifAnimationFrame frame;
424+
frame.pixbuf = set_pixbuf(context, error);
425+
frame.duration_ms = (uint64_t)(decoder->imageTiming.duration * 1000);
426+
427+
g_array_append_val(context->frames, frame);
292428

429+
context->prepared_func(g_array_index(context->frames, AvifAnimationFrame, 0).pixbuf,
430+
decoder->imageCount > 1 ? (GdkPixbufAnimation *)context : NULL, context->user_data);
431+
432+
while(decoder->imageIndex < decoder->imageCount - 1) {
433+
ret = avifDecoderNextImage(decoder);
434+
435+
if (ret == AVIF_RESULT_NO_IMAGES_REMAINING) {
436+
return TRUE;
437+
} else if (ret != AVIF_RESULT_OK) {
438+
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
439+
"Failed to decode all frames: %s", avifResultToString(ret));
440+
return FALSE;
441+
}
442+
443+
frame.pixbuf = set_pixbuf(context, error);
444+
frame.duration_ms = (uint64_t)(decoder->imageTiming.duration * 1000);
445+
446+
g_array_append_val(context->frames, frame);
447+
}
293448
return TRUE;
294449
}
295450

@@ -298,7 +453,7 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
298453
GdkPixbufModuleUpdatedFunc updated_func,
299454
gpointer user_data, GError ** error)
300455
{
301-
struct avif_context * context;
456+
AvifAnimation * context;
302457
avifDecoder * decoder;
303458

304459
g_assert(prepared_func != NULL);
@@ -310,7 +465,7 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
310465
return NULL;
311466
}
312467

313-
context = g_new0(struct avif_context, 1);
468+
context = g_object_new(GDK_TYPE_AVIF_ANIMATION, NULL);
314469
if (!context)
315470
return NULL;
316471

@@ -327,21 +482,21 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
327482

328483
static gboolean stop_load(gpointer data, GError ** error)
329484
{
330-
struct avif_context * context = (struct avif_context *) data;
485+
AvifAnimation * context = (AvifAnimation *) data;
331486
gboolean ret;
332487

333488
context->bytes = g_byte_array_free_to_bytes(context->data);
334489
context->data = NULL;
335490
ret = avif_context_try_load(context, error);
336491

337-
avif_context_free(context);
492+
g_object_unref(context);
338493

339494
return ret;
340495
}
341496

342497
static gboolean load_increment(gpointer data, const guchar * buf, guint size, GError ** error)
343498
{
344-
struct avif_context * context = (struct avif_context *) data;
499+
AvifAnimation * context = (AvifAnimation *) data;
345500
g_byte_array_append(context->data, buf, size);
346501
if (error)
347502
*error = NULL;

0 commit comments

Comments
 (0)