ugoku player

ugoira HTML5 zip player

@marcan42

What format?

  • GIFs are old, limited to 256 colors
  • Nobody supports APNG
    Except Firefox
  • Nobody supports MNG
  • Nobody agrees on a codec for <video>
    (and this isn't pikupikudouga)
  • Nobody wants to use Flash

Then what?

HTML5 to the rescue

Custom animation format

Use <canvas> to draw frames on the screen

Supported by all modern browsers

But how do we package up the frames?

ZIP bundles

JPEG or PNG frames inside an uncompressed ZIP archive

  • ZIP files are easy to parse
  • Generate using existing libraries
  • Parse using existing libraries on iOS/Android
  • Supports progressive load (with care)
  • Easy to extend in the future
  • PNG and JPEG frames are already compressed


Not a new idea (e.g. Android boot animations are JPEGs in a ZIP)

ZIP files

How do they work?

ZIP file structure

ZIP files are backwards

They start at the end

  • First read the End Of Central Directory Record
  • Then find the Central Directory Record
  • Then find the Local File Header
  • Then read the file data

Reading ZIPs in Javascript

HTML5 provides ways of handling binary data in JS

  • ArrayBuffer to store the ZIP file
  • Uint8Array to access byte ranges
  • DataView to parse ZIP fields (Uint16, Uint32, etc.)
  • Blob to represent embedded PNG/JPEG files
  • URL to map them to a virtual URL
  • Image to load them
  • <canvas> to display them

Progrewhat?

We don't want to wait for the whole ZIP to load before starting playback

Ideally

HTML5 would support progressive/partial XHR

Unfortunately

Only Firefox does (nonstandard extension)

Chunked download

Use the Range HTTP header to load the ZIP one chunk at a time

(and speed it up by queuing two chunks to be loaded simultaneously)

Not as ideal, but it works well

zip_player

Pixiv's ugoira player library

  • Loads ZIP file progressively
  • Parses ZIP headers and data
  • Handles timing and draws frames on the target <canvas>
  • Supports unpacked (non-zip) mode for upload preview

JSON metadata

Alongside the ZIP file, metadata provides frame durations


{
    mime_type: "image/jpeg",
    frames: [
        {file: "000001.jpg", delay: 40},
        {file: "000002.jpg", delay: 40},
        {file: "000003.jpg", delay: 40},
        // ...
    ]
}
					

Currently delivered out of band, in the page HTML

Usage example


var options = {
	canvas: document.getElementById("katakata"),
	source: "img/katakata.zip",
	metadata: katakata_meta,
	chunkSize: 300000,
	loop: true,
	autoStart: true,
	autosize: true
}
var p = new ZipImagePlayer(options);
					

In depth

「動くチルノちゃん」/「モフモフ」
pixiv.net/i/44524589

Loading state:
Frame:
Requests:
Last file loaded:
Chunks:
Frames:
Debug log:

Issues

Browsers...

  • IE < 10 and Android Browser < 4.0 do not support ArrayBuffer
    Ugoira not supported on these browsers
  • Objects are prefixed in many older browsers (and inconsistently)
    Check for every possible prefix to find them
  • Safari's network cache breaks horribly with Range headers
    Disable caching on Safari (WebKit bug 82672)
  • Some browsers don't support ArrayBuffer.slice()
    Use Uint8Array.subarray() (slower)
  • Android Browser 4.0-4.3 does not support Expose-Header
    Can't determine file length; disable progressive loading
  • iOS < 6 does not support Blob URLs
    Use manual base64 data: URLs (very slow)

Thank you


https://github.com/pixiv/zip_player

@marcan42