@@ -50,7 +50,10 @@ G_DECLARE_FINAL_TYPE(AvifAnimationIter, avif_animation_iter, GDK, AVIF_ANIMATION
50
50
51
51
G_DEFINE_TYPE (AvifAnimationIter , avif_animation_iter , GDK_TYPE_PIXBUF_ANIMATION_ITER );
52
52
53
+ /* Animation class functions */
54
+ static void avif_animation_finalize (GObject * obj )
53
55
{
56
+ AvifAnimation * context = (AvifAnimation * )obj ;
54
57
if (!context )
55
58
return ;
56
59
@@ -69,57 +72,153 @@ G_DEFINE_TYPE(AvifAnimationIter, avif_animation_iter, GDK_TYPE_PIXBUF_ANIMATION_
69
72
context -> bytes = NULL ;
70
73
}
71
74
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);
75
80
}
81
+ }
76
82
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 ;
78
87
}
79
88
80
- static gboolean avif_context_try_load ( struct avif_context * context , GError * * error )
89
+ static GdkPixbuf * avif_animation_get_static_image ( GdkPixbufAnimation * animation )
81
90
{
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
+ }
90
94
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 );
92
99
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 );
99
102
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 ;
106
105
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 ;
111
118
}
119
+ }
112
120
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
+ }
121
166
}
122
167
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 ;
123
222
image = decoder -> image ;
124
223
width = image -> width ;
125
224
height = image -> height ;
@@ -282,14 +381,70 @@ static gboolean avif_context_try_load(struct avif_context * context, GError ** e
282
381
g_free (icc_base64 );
283
382
}
284
383
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;
288
421
}
289
422
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 );
292
428
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
+ }
293
448
return TRUE;
294
449
}
295
450
@@ -298,7 +453,7 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
298
453
GdkPixbufModuleUpdatedFunc updated_func ,
299
454
gpointer user_data , GError * * error )
300
455
{
301
- struct avif_context * context ;
456
+ AvifAnimation * context ;
302
457
avifDecoder * decoder ;
303
458
304
459
g_assert (prepared_func != NULL );
@@ -310,7 +465,7 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
310
465
return NULL ;
311
466
}
312
467
313
- context = g_new0 ( struct avif_context , 1 );
468
+ context = g_object_new ( GDK_TYPE_AVIF_ANIMATION , NULL );
314
469
if (!context )
315
470
return NULL ;
316
471
@@ -327,21 +482,21 @@ static gpointer begin_load(GdkPixbufModuleSizeFunc size_func,
327
482
328
483
static gboolean stop_load (gpointer data , GError * * error )
329
484
{
330
- struct avif_context * context = (struct avif_context * ) data ;
485
+ AvifAnimation * context = (AvifAnimation * ) data ;
331
486
gboolean ret ;
332
487
333
488
context -> bytes = g_byte_array_free_to_bytes (context -> data );
334
489
context -> data = NULL ;
335
490
ret = avif_context_try_load (context , error );
336
491
337
- avif_context_free (context );
492
+ g_object_unref (context );
338
493
339
494
return ret ;
340
495
}
341
496
342
497
static gboolean load_increment (gpointer data , const guchar * buf , guint size , GError * * error )
343
498
{
344
- struct avif_context * context = (struct avif_context * ) data ;
499
+ AvifAnimation * context = (AvifAnimation * ) data ;
345
500
g_byte_array_append (context -> data , buf , size );
346
501
if (error )
347
502
* error = NULL ;
0 commit comments