@@ -50,7 +50,10 @@ G_DECLARE_FINAL_TYPE(AvifAnimationIter, avif_animation_iter, GDK, AVIF_ANIMATION
5050
5151G_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
328483static 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
342497static 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