Skip to content

feat(reader): replace MP4 transcoding with CADisplayLink-driven animated image player#623

Merged
everpcpc merged 1 commit intomainfrom
feat-animate
Mar 7, 2026
Merged

feat(reader): replace MP4 transcoding with CADisplayLink-driven animated image player#623
everpcpc merged 1 commit intomainfrom
feat-animate

Conversation

@everpcpc
Copy link
Copy Markdown
Owner

@everpcpc everpcpc commented Mar 7, 2026

Problem

The DIVINA reader transcodes animated GIF/WebP images to MP4 via AVAssetWriter (frame-by-frame decode → CVPixelBuffer → H.264) before playback with AVQueuePlayer. This transcode step is slow and adds visible loading time with a progress indicator before animated pages can play.

Approach

Replace the entire transcode-then-play pipeline with a CADisplayLink-driven approach that decodes frames lazily from CGImageSource:

  • AnimatedImageFrameDecoder owns a CGImageSource and provides frame count, per-frame duration (reusing the exact GIF/WebP unclamped/clamped delay logic), and on-demand single-frame decoding
  • AnimatedImagePlayerController drives a CADisplayLink, maintains a ring buffer of ~5 pre-decoded CGImage frames, advances frames based on accumulated elapsed time, and sets CALayer.contents directly
  • Platform-aware display link creation: CADisplayLink(target:selector:) on iOS, NSScreen.displayLink(target:selector:) on macOS

Scope

  • New: AnimatedImageFrameDecoder, AnimatedImagePlayerController, AnimatedImagePlayerView
  • Simplified: ReaderViewModel (removed transcoder state, preparation tasks, progress tracking), ReaderViewItemImageView (removed progress overlay and monitoring loop), NativeImagePageViewController (replaced AVPlayer stack with controller)
  • Deleted: AnimatedImageVideoTranscoder, LoopingVideoPlayerView
  • Net: -774 lines

Validation

  • make build passes on all three platforms (iOS, macOS, tvOS)
  • Manual: animated GIF/WebP pages play immediately without progress bar
  • Manual: animation loops smoothly, restarts on navigate-away-and-back
  • Manual: static images render normally (no regression)
  • Manual: tvOS builds and animated pages show static frame only

…ted image player

Animated GIF/WebP pages in the DIVINA reader were transcoded to MP4 via
AVAssetWriter before playback, which was slow. Replace the entire transcode
pipeline with a CADisplayLink-driven frame decoder that reads frames lazily
from CGImageSource, eliminating the conversion step entirely.

New files:
- AnimatedImageFrameDecoder: parses GIF/WebP frame durations, decodes
  individual frames on demand
- AnimatedImagePlayerController: drives playback via CADisplayLink with a
  ring buffer of ~5 pre-decoded frames and automatic eviction
- AnimatedImagePlayerView: SwiftUI wrapper (UIViewRepresentable on iOS,
  NSViewRepresentable on macOS, disabled on tvOS)

Removed:
- AnimatedImageVideoTranscoder (MP4 transcode pipeline)
- LoopingVideoPlayerView (AVQueuePlayer-based playback)

Simplified ReaderViewModel, ReaderViewItemImageView, and
NativeImagePageViewController by removing all transcoder references,
progress tracking, and preparation task management.
@everpcpc everpcpc merged commit 4a3d9a4 into main Mar 7, 2026
3 checks passed
@everpcpc everpcpc deleted the feat-animate branch March 7, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant