Skip to content

Proposed module interfaces

Brion Vibber edited this page Apr 23, 2017 · 44 revisions

Value types

YUVFormat

-> outsourced to yuv-buffer module:

  • width, height
  • chromaWidth, chromaHeight
  • cropLeft, cropTop, cropWidth, cropHeight
  • displayWidth, displayHeight

YUVPlane

-> outsourced to yuv-buffer module:

  • bytes: UInt8Array
  • stride: number

OGVVideoFormat

-> extends YUVFormat

YUVFrame

-> outsourced to yuv-buffer module:

  • format: YUVFormat
  • y: YUVPlane
  • u: YUVPlane
  • v: YUVPlane

OGVFrameBuffer

-> extends YUVFrame

  • timestamp: number
  • duration: number

OGVAudioFormat

  • channels: number
  • rate: number

AudioBuffer

outsourced to audio-feeder package

  • Array<Float32Array>

OGVAudioBuffer

Wrapper for raw audio data to potentially allow discontinuous audio tracks, changing audio formats and other fun things.

  • data: AudioBuffer
  • format: OGVAudioFormat
  • timestamp: number
    • start time in seconds
  • duration: number

OGVPacket

An encoded data packet, as retrieved from a demuxer and as sent into a decoder.

  • data: ArrayBuffer
  • timestamp: number
    • use start timestamp, not Ogg-style end timestamp
  • duration: number
    • duration of packet contents in seconds
  • keyframe: boolean
    • true if this is a valid start point for decoding

OGVTrackInfo

Internal data structure created by demuxer, passed to decoders for initialization.

  • codec:string
    • "theora", "v8", "vorbis", "opus", etc
  • type:string
    • "video" or "audio"
  • headers:Array<ArrayBuffer>
    • optional codec-specific setup headers
    • for Ogg formats, this is the header packets
    • for WebM Vorbis tracks, this is the de-laced Vorbis header data
    • empty otherwise

Interfaces

OGVTrackState

Opaque wrapper interface to per-track info & packet queue in the demuxer. Implementation of the queue and interface is up to the demuxer.

  • codec:string
    • "theora", "v8", "vorbis", "opus", etc
  • type:string
    • "video" or "audio"
  • format:OGVAudioFormat|OGVVideoFormat
    • track format as reported by the container format or initial header packets
    • beware that actual decoded data may vary in format, such as in VP8/VP9 frame size changes in WebM

Tags, comments, metadata?

OGVInputStream

Abstraction for a readable, optionally seekable, buffered byte input stream that can be read asynchronously. An instance is passed into the demuxer instead of shoving data into the demuxer from the outside. If feeding data is desired, create a suitable OGVInputStream wrapper for your buffers!

Things like network setup and details of buffering are done outside this interface; the demuxers need to be able to work with MSE analogues and can't assume direct net access.

  • seekable: boolean
    • true if underlying stream can be seeked
  • eof: boolean
    • true if reached end of file
    • may change state during read() or seek()
  • offset: number
    • current byte offset of reader
  • length: number
    • total byte length of file/buffer, or -1 for unknown
  • bytesAvailable(max:number=Infinity): number
    • count of available buffered bytes that can be read synchronously from the current position
    • may be 0!
    • pass optional 'max' parameter to reduce search time within cache if you only care about hitting a certain number
  • buffer(nbytes:number): Promise
    • wait until at least nbytes are available in the buffer or eof
    • invalid if seeking or buffering
  • buffering: boolean
    • true if a buffer() operation is in progress
  • readBytes(dest:Uint8Array): number
    • immediately read bytesAvailable(dest.byteLength) bytes from buffer into the given dest array, returning the actual number of bytes read
    • call buffer(dest.byteLength) first if need to wait for data
    • if eof is reached, will return fewer bytes than asked -- even 0
    • may change offset, eof state
    • invalid if seeking or buffering
  • seek(offset): Promise
    • seek to the target offset from the beginning of the file, if seekable
    • may change offset, eof state
    • invalid if seeking or buffering
    • invalid if not seekable
    • aborts any prior running download, may start a new one
  • seeking: boolean
    • true if a seek operation is in progress
  • abort()
    • cancel ongoing buffer or seek operation
    • can still use the object to trigger more reads
  • close()
    • cancel all operations and close resources
    • can no longer use the object!

OGVDemuxer

Low-level demuxer interface for format support plugins to implement. Each OGVDemuxer is given control of an underlying OGVInputStream and can read and seek on it as necessary. Beware that not all input streams are seekable; they may represent live streams that cannot be seeked on, or an append-only series of buffers as with Media Source Extensions.

  • loaded: boolean
    • true once init() succeeds and metadata is loaded
  • duration: number
    • duration in seconds if known, or NaN if unknown, or +Infinity if livestream
  • audio: OGVTrackState|null
    • null if no audio track, or an OGVTrack with info & packet queue
  • video: OGVTrackState|null
    • null if no video track, or an OGVTrack with info & packet queue
  • seekable: boolean
    • true if the data stream looks seekable and the underlying input stream is seekable
  • eof: boolean
    • true if at end of data stream
    • may change state from init() or nextPacket() calls
  • init(stream:OGVInputStream):Promise
    • read enough metadata on the stream to determine which tracks are available and queue up their header packets.
    • invalid if loaded
    • loaded, duration, tracks, seekable will be filled out on success
  • demuxAudio(): Promise<OGVPacket>
    • demux until next audio packet or end of stream
    • resolves with the packet, or null if eof
    • if end of input stream reached, set eof
    • invalid if already demuxing or seeking
  • demuxVideo(): Promise<OGVPacket>
    • demux until next video packet or end of stream
    • resolves with the packet, or null if eof
    • if end of input stream reached, set eof
    • invalid if already demuxing or seeking
  • demuxing: boolean
    • true if a demuxing operation is in progress
  • seek(targetTime): Promise<actualTime:number>
    • seek to a keyframe point at or before the target time
    • (higher-level code will be responsible for further decoding to an exact time)
    • invalid if not loaded
    • invalid if not seekable
    • cancels any prior demux(), seek() calls, rejecting their promises. (The underlying demuxer is free to load as much data as it wants though, for instance to finish loading partially-loaded index cues before going on to complete the target seek)
    • unset eof if necessary!
  • seeking: boolean
    • true if a seek operation is in progress
  • abort()
    • cancel any ongoing demux(), seek() calls
    • may call abort() on the underlying OGVInputStream
    • can issue additional seek() calls afterwards, at which point may call demux() again
  • close()
    • free any resources, terminate any threads
    • cancels any ongoing init(), demux(), seek() calls

OGVAudioDecoder

  • loaded: boolean
  • init(trackInfo:OGVTrackInfo): Promise
    • invalid if loaded
    • if using a background thread, this is the time to launch it
    • loaded will be true after successful completion
    • initial header packets may be provided by the demuxer in the track state, but must already have been demuxed
  • decode(packet:OGVPacket):Promise<buffer:OGVAudioBuffer|null>
    • decode a packet into raw audio data asynchronously
    • invalid if not loaded
    • headers may return null instead of a buffer...
    • headers may occur in the middle of a stream in cases such as Ogg chaining! this should reinitialize the decoder.
    • calls may be stacked/pipelined!
  • flush():Promise
    • clear state and prepare for a seek or other reset
    • invalid if not loaded
    • cancels any prior decode(), flush() calls
  • close():void
    • free any resources, terminate any threads
    • cancels any prior init(), decode(), flush() calls

OGVVideoDecoder

  • loaded: boolean
  • init(track:OGVTrackState) Promise
    • invalid if loaded
    • if using a background thread, this is the time to launch it
    • loaded will be filled out after successful completion
    • initial header packets may be provided by the demuxer in the track state, but must already have been demuxed
  • decode(packet:OGVPacket):Promise<frame:OGVFrameBuffer|null>
    • decode a packet into a frame asynchronously
    • invalid if not loaded
    • headers and duplicate frames may return null instead of a frame...
    • headers may occur in the middle of a stream in cases such as Ogg chaining! this should reinitialize the decoder.
    • beware that video format of decoded frames may vary, in cases like Ogg chaining or VP8/VP9 variable frame sizes.
    • calls may be stacked/pipelined!
  • flush():Promise
    • clear state and prepare for a seek or other reset
    • invalid if not loaded
    • cancels any prior decode(), flush() calls
  • close():void
    • free any resources, terminate any threads
    • cancels any prior init(), decode(), flush() calls