Repository navigation
Play animated GIF files as video - #11718
Closed
mikeysklar wants to merge 11 commits into
Closed
mikeysklar wants to merge 11 commits into
mikeysklar wants to merge 11 commits into
Conversation
The rect was only computed on a move or transform, using the source's size. A VideoBuffer added to a Group before play() kept an empty rect. A plain buffer target drew nothing until it moved. A framebuffer target still got its frames, but compositing and overlay repaint were wrong. This also clears a stale rect when a source of another size is played again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plain buffer move only repainted the area it left. The new location stayed stale until the next frame repainted it. Mark it dirty as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
on_frame gets a changed rect in source coordinates, and the refresh only repaints that part. NULL means the whole frame changed and the next frame repaints all of it. A rect gives a source a protocol type with no displayio dependency. mipicsi passes NULL. get_refresh_areas takes the landed frame and vacated area in one critical section. A frame landing during a refresh stays for the next one, unless it passed NULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fit check assumed a contiguous frame of height * row_bytes. A source that writes each row at the framebuffer stride ends (height - 1) strides in, so a narrow frame low in the framebuffer could run past its end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move opening a file by name and reading the GIF header into helpers so another GIF user can share them. OnDiskGif behaves the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A source calls the destination's on_eos when it will write no more frames. VideoBuffer then stops it the next time playing, source or a refresh looks, like audio outputs stop a finished sample, and keeps its last frame shown. A framebuffer target drops that frame when moved or hidden, since the repaint overwrites it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GifDecoder plays an animated GIF into a videocore.VideoBuffer as RGB565 frames, reporting each frame's changed rect. It follows the frame delays and loop count, and reports the end of the stream on the last loop or a read error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 2, 2026
mikeysklar
marked this pull request as ready for review
November 2, 2026 20:18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
Collaborator
Author
|
Replaced by #11738, opened from an adafruit branch so the three PRs stack. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
videogif.GifDecoderplays a GIF into avideocore.VideoBuffer.Why
GIFs store which area changed and how long each frame lasts, so slow displays can redraw less.
Part 1 of 3 toward GIF video on e-paper, followed by #11719 and #11720. Merges first, needs no other PR.
p4_7in_gif_plainbuffer_landscape.mp4
Metro ESP32-P4 with Raspberry Pi Touch Display 2, filmed on a dev build of all 3 PRs. The teapot is
teapot_1bit_320.gif(320x240, 120 frames), decoded at 16 bit into a plain buffer.Clip code:
code.pyChanges
play()staying blank.on_framegainschanged,NULLfor the whole frame. The camera passesNULL.OnDiskGif, same behavior.CIRCUITPY_VIDEOCOREandCIRCUITPY_GIFIOare on.playinggoes False after the last loop, a read error ordeinit().bytearray), or framebuffer (FramebufferDisplay, read back to check pixels)Tested
Metro ESP32-P4, Raspberry Pi Touch Display 2,
color_depth=16, Ubuntu host, 3 trials per row.CircuitPython 11.0.0-alpha.2 dev builds of this branch, before the rebase.
video.x = 0playingFalse at the enddeinit()mem_freeOnDiskGifon Metro RP2040, no video, main vs this branchnext_frame, teapot in palette modedeinit()at VM end, ASanplay()after a GIF endedpre-commitpasses on the final branch.Test files
Test GIFs:
make_gifs.pyand the three GIFstg_once.gifplays once,tg_loop2.gifloops twice,tg_inf.gifloops forever.Test code:
g_basicon Metro ESP32-P4 (display setup, helpers, case)Serial output from that run
Limits
audiocore.WaveFile(from source)ValueError, as withOnDiskGifplay()after a GIF endedsourceis NonePanel safety
This PR doesn't change how any display is driven. The fast e-paper updates in #11719 go past panel makers' refresh limits, and its
EPaperDisplaydocs now carry a warning.AI assistance
Written with Claude Code.
🤖 Generated with Claude Code