Skip to content

Commit e600723

Browse files
committed
Re-design (& re-implement) video_anim to support any video domain
1 parent 1ebb102 commit e600723

File tree

5 files changed

+511
-490
lines changed

5 files changed

+511
-490
lines changed

kos/include/libvideo/gfx/anim.h

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <kos/anno.h>
3333
#include <kos/refcnt.h>
3434

35+
#include "../color.h"
3536
#include "../types.h"
3637

3738
#ifdef __CC__
@@ -43,110 +44,105 @@ struct video_anim;
4344

4445
typedef __uint32_t video_anim_frame_id;
4546

46-
struct video_anim_frameinfo {
47-
struct __timeval64 vafi_showfor; /* How long to display the frame before showing the next */
48-
video_anim_frame_id vafi_frameid; /* ID (# of frames that came before) of the associated frame */
47+
/* Frame data created when the first frame is read, and updated whenever a next frame is read.
48+
* You must treat this data as READ-ONLY if you ever intend to call `video_anim_nextframe()'
49+
* using this data again. */
50+
struct video_anim_frame {
51+
__ATTR_NONNULL_T((1)) void /* Destructor callback for frame data */
52+
(LIBVIDEO_GFX_CC *vaf_fini)(struct video_anim_frame *__restrict __self);
53+
REF struct video_buffer *vaf_frame; /* [1..1] Current frame (and previous frame during) */
54+
struct __timeval64 vaf_showfor; /* How long to display the frame before showing the next */
55+
video_anim_frame_id vaf_frameid; /* ID of this frame */
56+
video_color_t vaf_colorkey; /* Frame color key, or "0" if not needed */
57+
58+
/* Animation-specific frame data goes here... */
4959
};
5060

61+
#define video_anim_frame_fini(self) ((self)->vaf_fini)(self)
62+
63+
5164
struct video_anim_ops {
5265
__ATTR_NONNULL_T((1)) void
5366
(LIBVIDEO_GFX_CC *vao_destroy)(struct video_anim *__restrict __self);
5467

55-
/* Start a new animation cycle and return a video buffer for the first frame.
56-
* - The video contents of the returned buffer should NOT be modified.
68+
/* Size of `struct video_anim_frame' that the
69+
* caller must use with this type of animation. */
70+
size_t vao_sizeof_frame;
71+
72+
/* Start a new animation cycle and initialize `__frame' for the first frame.
73+
* - The video contents of the buffer included in `__frame' should NOT be modified.
5774
* - Make a call to `vao_nextframe()' to advance to the next frame.
75+
* - Once done, finalize frame data using `video_anim_frame_fini(__frame)'
76+
* - The given `__frame' must be at least `vao_sizeof_frame' bytes large,
77+
* and be aligned according to standard alignment (`alloca()' and `malloc()'
78+
* are both fine for allocating this buffer))
5879
*
5980
* To render the animation, the caller should do this:
60-
* >> struct video_anim_frameinfo info, nextinfo;
61-
* >> REF struct video_screen *screen = screen_buffer_create(NULL);
62-
* >> REF struct video_anim *anim = video_anim_open("/vat/anim.gif");
63-
* >> REF struct video_buffer *frame = video_anim_firstframe(anim, &info);
6481
* >> struct video_gfx screen_gfx;
6582
* >> struct video_gfx frame_gfx;
6683
* >> struct timeval frame_start, frame_end;
67-
* >> struct timeval tv_delay, tv_spent;
84+
* >> struct timeval tv_delay, tv_spent, showfor;
6885
* >> struct timespec ts_delay;
86+
* >> REF struct video_screen *screen;
87+
* >> REF struct video_anim *anim;
88+
* >> struct video_anim_frame *data;
89+
* >>
90+
* >> screen = screen_buffer_create(NULL);
91+
* >> anim = video_anim_open("/var/anim.gif");
92+
* >> data = (struct video_anim_frame *)malloca(video_anim_sizeof_frame(anim));
93+
* >>
94+
* >> video_anim_firstframe(anim, data);
6995
* >> video_buffer_getgfx((struct video_buffer *)screen, &screen_gfx,
7096
* >> GFX_BLENDMODE_OVERRIDE, VIDEO_GFX_F_NORMAL, 0);
7197
* >> gettimeofday(&frame_start, NULL);
7298
* >> for (;;) {
7399
* >>
74100
* >> // Display current frame on-screen (here: stretched)
75-
* >> video_buffer_getgfx(frame, &frame_gfx,
101+
* >> video_buffer_getgfx(data->vaf_frame, &frame_gfx,
76102
* >> GFX_BLENDMODE_OVERRIDE, VIDEO_GFX_F_NORMAL, 0);
77103
* >> video_gfx_stretch(&screen_gfx, 0, 0, VIDEO_DIM_MAX, VIDEO_DIM_MAX,
78104
* >> &frame_gfx, 0, 0, VIDEO_DIM_MAX, VIDEO_DIM_MAX);
79105
* >> struct video_crect update_rect = VIDEO_CRECT_INIT_FULL;
80106
* >> screen_buffer_updaterect(screen, &update_rect);
81107
* >>
82108
* >> // Load next frame as part of render delay
83-
* >> nextinfo = info;
84-
* >> video_anim_nextframe(&anim, frame, &nextinfo);
109+
* >> showfor = data->vaf_showfor;
110+
* >> video_anim_nextframe(&anim, data);
85111
* >>
86112
* >> // Wait until the next frame should be rendered
87113
* >> gettimeofday(&frame_end, NULL);
88114
* >> timeval_sub(&tv_spent, &frame_end, &frame_start);
89-
* >> timeval_sub(&tv_delay, &info.vafi_showfor, &tv_spent);
115+
* >> timeval_sub(&tv_delay, &showfor, &tv_spent);
90116
* >> timeval_add(&frame_end, &frame_end, &tv_delay);
91117
* >> TIMEVAL_TO_TIMESPEC(&tv_delay, &ts_delay);
92118
* >> frame_start = frame_end;
93-
* >> info = nextinfo;
94119
* >> if (ts_delay.tv_sec >= 0)
95120
* >> nanosleep(&ts_delay, NULL);
96121
* >> }
97122
*
98-
* @return: * : A video buffer containing the first frame of the animation
99-
* If you do not intend to render any of the other frame, you
100-
* can simply decref() the animation and use this buffer as you
101-
* would one returned by `video_buffer_open()'
102-
* @return: NULL: Failed to load first frame (s.a. `errno') */
103-
__ATTR_WUNUSED_T __ATTR_IN_T(1) __ATTR_OUT_T(2) __REF struct video_buffer *
123+
* @return: 0 : Success: `__frame' was initialized and the caller must eventually finalize it
124+
* @return: -1: Failed to load first frame (s.a. `errno') */
125+
__ATTR_WUNUSED_T __ATTR_IN_T(1) __ATTR_OUT_T(2) int
104126
(LIBVIDEO_GFX_CC *vao_firstframe)(struct video_anim const *__restrict __self,
105-
struct video_anim_frameinfo *__restrict __info);
127+
struct video_anim_frame *__restrict __frame);
106128

107-
/* Update pixel data of `__buf' to contain the contents of the next frame in line.
108-
* For this purpose, assume that on entry, `__buf' was returned by `vao_firstframe'
109-
* or a preceding call to `vao_nextframe', and currently contains a redner of the
110-
* frame identified by `IN(__info->vafi_frameid)'.
111-
*
112-
* This function may then update the contents of `__buf' and `__info' such that
113-
* upon successful return (return == 0), `__info->vafi_frameid' has been increment
114-
* or reset back to `0', and `__buf' now contains a render of the next frame. It
115-
* may also simply return some other video buffer (iow: return != __buf) is allowed
116-
*
117-
* CAUTION: This function is not thread-safe when `__buf' is simultaneously being
118-
* used by another thread, or if someone is still holding a video_lock.
119-
* This function is also allowed to modify `__buf' in way not normally
120-
* allowed (including changing its codec and/or palette, as well as the
121-
* memory used to back any potential video lock). The only thing it is
122-
* not allowed to changed are the buffer's dimensions.
123-
*
124-
* CAUTION: The video buffer returned by `vao_firstframe' might contain some extra
125-
* out-of-band data that is then needed/used by this function to render
126-
* the next frame. Do **NOT** pass a video buffer that wasn't returned by
127-
* `vao_firstframe', and do **NOT** try to skip frames by changing the
128-
* value in `__info->vafi_frameid' between calls.
129+
/* Update `__frame' (and specifically: `__frame->vaf_frame') to contain the contents
130+
* of the next frame in line.
129131
*
130-
* @return: * : A video buffer with the same resolution as `__buf' (or possibly
131-
* just `__buf' again), that contains a render of the next frame.
132-
* In this case, this function semantically inherited a reference
133-
* to the given `__buf' (meaning that if another buffer is returned,
134-
* the call will have video_buffer_decref'd the given `__buf')
135-
* @return: NULL: Failed to render next frame (s.a. `errno'). In this case, no
136-
* reference to `__buf' has been inherited, though the pixel
137-
* contents of `__buf' may have been modified and may even look
138-
* corrupted now (though semantically speaking, `__buf' is still
139-
* guarantied to be in a consistent state). */
140-
__ATTR_WUNUSED_T __ATTR_IN_T(1) __ATTR_INOUT_T(2) __ATTR_INOUT_T(3) __REF struct video_buffer *
132+
* @return: 0 : Success: `__frame' was updated to contain the next frame.
133+
* @return: -1: Failed to render next frame (s.a. `errno'). In this case, no
134+
* reference to `__buf' has been inherited, though the pixel
135+
* contents of `__buf' may have been modified and may even look
136+
* corrupted now (though semantically speaking, `__buf' is still
137+
* guarantied to be in a consistent state). */
138+
__ATTR_WUNUSED_T __ATTR_IN_T(1) __ATTR_INOUT_T(2) int
141139
(LIBVIDEO_GFX_CC *vao_nextframe)(struct video_anim const *__restrict __self,
142-
/*inherit(on_success)*/ __REF struct video_buffer *__restrict __buf,
143-
struct video_anim_frameinfo *__restrict __info);
140+
struct video_anim_frame *__restrict __frame);
144141
};
145142

146-
#define video_anim_firstframe(self, info) \
147-
(*(self)->va_ops->vao_firstframe)(self, info)
148-
#define video_anim_nextframe(self, buf, info) \
149-
(*(self)->va_ops->vao_nextframe)(self, buf, info)
143+
#define video_anim_sizeof_frame(self) ((self)->va_ops->vao_sizeof_frame)
144+
#define video_anim_firstframe(self, frame) (*(self)->va_ops->vao_firstframe)(self, frame)
145+
#define video_anim_nextframe(self, frame) (*(self)->va_ops->vao_nextframe)(self, frame)
150146

151147
struct video_anim {
152148
struct video_anim_ops const *va_ops; /* [1..1][const] Video animation operators */

kos/src/apps/showpic/main.c

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include <err.h>
3737
#include <format-printer.h>
38+
#include <malloca.h>
3839
#include <stdbool.h>
3940
#include <stddef.h>
4041
#include <stdint.h>
@@ -216,7 +217,7 @@ do_showpic(struct video_buffer *screen,
216217
struct video_buffer *image,
217218
struct video_font *font,
218219
char const *filename,
219-
struct video_anim_frameinfo *frameinfo) {
220+
struct video_anim_frame *frameinfo) {
220221
struct video_gfx screen_gfx;
221222
struct video_gfx image_gfx;
222223
video_dim_t blit_w, blit_h;
@@ -296,7 +297,7 @@ do_showpic(struct video_buffer *screen,
296297
#endif
297298

298299
/* Display the image */
299-
#if 0
300+
#if 1
300301
video_gfx_stretch(&screen_gfx, blit_x, blit_y, blit_w, blit_h,
301302
&image_gfx, 0, 0,
302303
video_gfx_getclipw(&image_gfx),
@@ -344,7 +345,7 @@ do_showpic(struct video_buffer *screen,
344345
video_gfx_getcliph(&image_gfx));
345346
}
346347
}
347-
#elif 1
348+
#elif 0
348349
{
349350
struct video_gfx flipgfx = image_gfx;
350351
// video_gfx_lrot90(&flipgfx);
@@ -513,7 +514,7 @@ do_showpic(struct video_buffer *screen,
513514
fd.vfp_bg_fg_colors[1] = VIDEO_COLOR_WHITE;
514515
gfx_printf("\n");
515516

516-
gfx_printf("%s#%u\n", filename, (unsigned int)frameinfo->vafi_frameid);
517+
gfx_printf("%s#%u\n", filename, (unsigned int)frameinfo->vaf_frameid);
517518
dump_buffer_specs(image, &fd);
518519

519520
gfx_printf("Screen:\n");
@@ -540,10 +541,8 @@ int main(int argc, char *argv[]) {
540541
REF struct screen_buffer *screen;
541542
REF struct video_display *display = NULL;
542543
REF struct video_buffer *bscreen;
543-
REF struct video_buffer *frame;
544544
REF struct video_anim *anim;
545-
struct video_anim_frameinfo frame_info;
546-
struct video_anim_frameinfo frame_nextinfo;
545+
struct video_anim_frame *frame;
547546
struct timeval frame_start, frame_end;
548547

549548
if (argc != 2) {
@@ -652,19 +651,18 @@ int main(int argc, char *argv[]) {
652651
* - src format caching: ~95% spent sleeping (=> x20 pixel output possible)
653652
* - dst format caching: ~97% spent sleeping (=> x30 pixel output possible) */
654653
#if 0
655-
anim = video_anim_cached(anim, NULL, NULL, VIDEO_BUFFER_AUTO);
656-
#elif 0
657-
anim = video_anim_cached(anim,
658-
bscreen->vb_format.vf_codec,
659-
bscreen->vb_format.vf_pal,
660-
VIDEO_BUFFER_AUTO);
654+
anim = video_anim_cached(anim, NULL);
655+
#elif 1
656+
anim = video_anim_cached(anim, &bscreen->vb_format);
661657
#endif
662658
if unlikely(!anim)
663659
err(EXIT_FAILURE, "Failed to cache animation");
660+
frame = (struct video_anim_frame *)malloca(video_anim_sizeof_frame(anim));
661+
if unlikely(!frame)
662+
err(EXIT_FAILURE, "Failed to allocate animation frame reader");
664663

665664
/* Load first frame of a potentially animated image */
666-
frame = video_anim_firstframe(anim, &frame_info);
667-
if unlikely(!frame)
665+
if unlikely(video_anim_firstframe(anim, frame))
668666
err(EXIT_FAILURE, "Failed to load frame");
669667

670668
/* Clear screen */
@@ -679,11 +677,11 @@ int main(int argc, char *argv[]) {
679677
/* Render loop */
680678
gettimeofday(&frame_start, NULL);
681679
for (;;) {
682-
struct timeval tv_delay, tv_spent;
680+
struct timeval tv_delay, tv_spent, tv_showfor;
683681
struct timespec ts_delay;
684682

685683
/* Render frame */
686-
do_showpic(bscreen, frame, font, argv[1], &frame_info);
684+
do_showpic(bscreen, frame->vaf_frame, font, argv[1], frame);
687685
if (display) {
688686
syslog(LOG_DEBUG, "BEGIN: video_display_updaterect()\n");
689687
video_display_updaterect(display, &RECT_FULL);
@@ -692,28 +690,31 @@ int main(int argc, char *argv[]) {
692690
screen_buffer_updaterect(screen, &CRECT_FULL);
693691

694692
/* Load next frame as part of render delay */
695-
frame_nextinfo = frame_info;
696-
frame = video_anim_nextframe(anim, frame, &frame_nextinfo);
697-
if (!frame) {
693+
tv_showfor = frame->vaf_showfor;
694+
if (video_anim_nextframe(anim, frame)) {
698695
/* NOTE: Technically would need to decref the "frame" passed
699696
* as parameter, but we don't care about leaks since
700697
* everything gets cleaned up when we exit anyways. */
701-
err(EXIT_FAILURE, "Failed to load frame after %u",
702-
(unsigned int)frame_info.vafi_frameid);
698+
err(EXIT_FAILURE, "Failed to load frame at %u",
699+
(unsigned int)frame->vaf_frameid);
703700
}
704701

705702
/* Wait until the next frame should be rendered */
706703
#if 0
704+
(void)frame_start;
705+
(void)frame_end;
706+
(void)tv_showfor;
707+
(void)tv_spent;
708+
(void)tv_delay;
709+
(void)ts_delay;
707710
getchar();
708-
frame_info = frame_nextinfo;
709711
#else
710712
gettimeofday(&frame_end, NULL);
711713
timeval_sub(&tv_spent, &frame_end, &frame_start);
712-
timeval_sub(&tv_delay, &frame_info.vafi_showfor, &tv_spent);
714+
timeval_sub(&tv_delay, &tv_showfor, &tv_spent);
713715
timeval_add(&frame_end, &frame_end, &tv_delay);
714716
TIMEVAL_TO_TIMESPEC(&tv_delay, &ts_delay);
715717
frame_start = frame_end;
716-
frame_info = frame_nextinfo;
717718
if (ts_delay.tv_sec >= 0)
718719
nanosleep(&ts_delay, NULL);
719720
#endif

0 commit comments

Comments
 (0)