Files
questshock/modding/hacked/ss1/content/movie/internal/format/Entry.go
T

306 lines
8.4 KiB
Go

package format
import (
"bytes"
"io"
"github.com/inkyblackness/hacked/ss1/content/bitmap"
"github.com/inkyblackness/hacked/ss1/content/movie/internal/compression"
"github.com/inkyblackness/hacked/ss1/serial"
)
// EntryBucketPriority describes the general priority of the bucket.
// Lower numbers are put before higher numbers if the bucket has the same timestamp.
type EntryBucketPriority int
// List of entry bucket priorities.
const (
EntryBucketPriorityAudio = 0
EntryBucketPriorityVideoControl = 1
EntryBucketPrioritySubtitleControl = 2
EntryBucketPrioritySubtitle = 3
EntryBucketPriorityFrame = 4
)
// EntryBucket is a set of entries that need to be together within the stream.
// This exists mainly to cover special cases of entries within a stream that have no valid timestamp.
type EntryBucket struct {
// Priority helps in merging content from multiple buckets.
Priority EntryBucketPriority
// Timestamp specifies at which time the bucket should be inserted into the stream.
// This is typically derived from one of the timestamps of the contained entries.
Timestamp Timestamp
// Entries is the list of entries within this bucket.
Entries []Entry
}
// Entry describes a timestamped block from a MOVI container.
type Entry struct {
// Timestamp marks the beginning time of the entry.
Timestamp Timestamp
// Data is a type specific information of a movie.
Data EntryData
}
// EntryData describes one entry in a MOVI container.
type EntryData interface {
// Type describes the content type of the data.
Type() DataType
// Bytes returns the raw bytes of the entry.
Bytes() []byte
}
// UnknownEntryData is an entry that is not know to this codebase.
type UnknownEntryData struct {
DataType DataType
Raw []byte
}
// UnknownEntryFrom decodes an entry from given data.
func UnknownEntryFrom(dataType DataType, r io.Reader, dataSize int) (UnknownEntryData, error) {
data := UnknownEntryData{
DataType: dataType,
Raw: make([]byte, dataSize),
}
coder := serial.NewDecoder(r)
coder.Code(data.Raw)
return data, coder.FirstError()
}
// Type describes the entry.
func (data UnknownEntryData) Type() DataType {
return data.DataType
}
// Bytes returns the raw bytes of the entry.
func (data UnknownEntryData) Bytes() []byte {
return data.Raw
}
// LowResVideoEntryData is a compressed low-resolution video frame.
type LowResVideoEntryData struct {
BoundingBox [4]uint16
Packed []byte
}
// LowResVideoEntryFrom decodes an entry from given data.
func LowResVideoEntryFrom(r io.Reader, dataSize int) (LowResVideoEntryData, error) {
var data LowResVideoEntryData
coder := serial.NewDecoder(r)
coder.Code(&data.BoundingBox)
data.Packed = make([]byte, dataSize-int(coder.CurPos()))
coder.Code(data.Packed)
return data, coder.FirstError()
}
// Type describes the entry.
func (data LowResVideoEntryData) Type() DataType {
return DataTypeLowResVideo
}
// Bytes returns the raw bytes of the entry.
func (data LowResVideoEntryData) Bytes() []byte {
buf := bytes.NewBuffer(nil)
coder := serial.NewEncoder(buf)
coder.Code(data.BoundingBox)
coder.Code(data.Packed)
return buf.Bytes()
}
// HighResVideoEntryData is a compressed high-resolution video frame.
type HighResVideoEntryData struct {
Bitstream []byte
Maskstream []byte
}
// HighResVideoEntryFrom decodes an entry from given data.
func HighResVideoEntryFrom(r io.Reader, dataSize int) (HighResVideoEntryData, error) {
var data HighResVideoEntryData
coder := serial.NewDecoder(r)
var maskstreamOffset uint16
coder.Code(&maskstreamOffset)
data.Bitstream = make([]byte, int(maskstreamOffset)-int(coder.CurPos()))
coder.Code(data.Bitstream)
data.Maskstream = make([]byte, dataSize-int(coder.CurPos()))
coder.Code(data.Maskstream)
return data, coder.FirstError()
}
// Type describes the entry.
func (data HighResVideoEntryData) Type() DataType {
return DataTypeHighResVideo
}
// Bytes returns the raw bytes of the entry.
func (data HighResVideoEntryData) Bytes() []byte {
buf := bytes.NewBuffer(nil)
coder := serial.NewEncoder(buf)
maskstreamOffset := uint16(len(data.Bitstream)) + 2
coder.Code(&maskstreamOffset)
coder.Code(data.Bitstream)
coder.Code(data.Maskstream)
return buf.Bytes()
}
// AudioEntryData is an entry with audio samples.
type AudioEntryData struct {
Samples []byte
}
// AudioEntryFrom decodes an entry from given data.
func AudioEntryFrom(r io.Reader, dataSize int) (AudioEntryData, error) {
var data AudioEntryData
data.Samples = make([]byte, dataSize)
coder := serial.NewDecoder(r)
coder.Code(data.Samples)
return data, coder.FirstError()
}
// Type describes the entry.
func (data AudioEntryData) Type() DataType {
return DataTypeAudio
}
// Bytes returns the raw bytes of the entry.
func (data AudioEntryData) Bytes() []byte {
return data.Samples
}
// SubtitleEntryData is an entry with Subtitle samples.
type SubtitleEntryData struct {
Control SubtitleControl
Text []byte
}
// SubtitleEntryFrom decodes an entry from given data.
func SubtitleEntryFrom(r io.Reader, dataSize int) (SubtitleEntryData, error) {
var data SubtitleEntryData
coder := serial.NewDecoder(r)
var header SubtitleHeader
coder.Code(&header)
data.Control = header.Control
if header.TextOffset > coder.CurPos() {
coder.Code(make([]byte, header.TextOffset-coder.CurPos()))
}
data.Text = make([]byte, dataSize-int(coder.CurPos()))
coder.Code(data.Text)
return data, coder.FirstError()
}
// Type describes the entry.
func (data SubtitleEntryData) Type() DataType {
return DataTypeSubtitle
}
// Bytes returns the raw bytes of the entry.
func (data SubtitleEntryData) Bytes() []byte {
header := SubtitleHeader{
Control: data.Control,
TextOffset: SubtitleDefaultTextOffset,
}
buf := bytes.NewBuffer(nil)
coder := serial.NewEncoder(buf)
coder.Code(&header)
coder.Code(make([]byte, int(header.TextOffset-coder.CurPos())))
coder.Code(data.Text)
return buf.Bytes()
}
// PaletteEntryData is an entry with a palette.
type PaletteEntryData struct {
Colors bitmap.Palette
}
// PaletteEntryFrom decodes an entry from given data.
func PaletteEntryFrom(r io.Reader) (PaletteEntryData, error) {
var data PaletteEntryData
coder := serial.NewDecoder(r)
coder.Code(&data.Colors)
return data, coder.FirstError()
}
// Type describes the entry.
func (data PaletteEntryData) Type() DataType {
return DataTypePalette
}
// Bytes returns the raw bytes of the entry.
func (data PaletteEntryData) Bytes() []byte {
buf := bytes.NewBuffer(nil)
coder := serial.NewEncoder(buf)
coder.Code(&data.Colors)
return buf.Bytes()
}
// PaletteResetEntryData marks a reset of the palette.
type PaletteResetEntryData struct {
}
// PaletteResetEntryFrom decodes an entry from given data.
func PaletteResetEntryFrom() (PaletteResetEntryData, error) {
return PaletteResetEntryData{}, nil
}
// Type describes the entry.
func (data PaletteResetEntryData) Type() DataType {
return DataTypePaletteReset
}
// Bytes serializes the entry.
func (data PaletteResetEntryData) Bytes() []byte {
return nil
}
// PaletteLookupEntryData contains a list of palette indices.
type PaletteLookupEntryData struct {
List []byte
}
// PaletteLookupEntryFrom decodes an entry from given data.
func PaletteLookupEntryFrom(r io.Reader, dataSize int) (PaletteLookupEntryData, error) {
var data PaletteLookupEntryData
data.List = make([]byte, dataSize)
coder := serial.NewDecoder(r)
coder.Code(data.List)
return data, coder.FirstError()
}
// Type describes the entry.
func (data PaletteLookupEntryData) Type() DataType {
return DataTypePaletteLookupList
}
// Bytes serializes the entry.
func (data PaletteLookupEntryData) Bytes() []byte {
return data.List
}
// ControlDictionaryEntryData contains control words for compression.
type ControlDictionaryEntryData struct {
Words []compression.ControlWord
}
// ControlDictionaryEntryFrom decodes an entry from given data.
func ControlDictionaryEntryFrom(r io.Reader, dataSize int) (ControlDictionaryEntryData, error) {
var data ControlDictionaryEntryData
coder := serial.NewDecoder(r)
b := make([]byte, dataSize)
coder.Code(b)
if coder.FirstError() != nil {
return data, coder.FirstError()
}
var err error
data.Words, err = compression.UnpackControlWords(b)
return data, err
}
// Type describes the entry.
func (data ControlDictionaryEntryData) Type() DataType {
return DataTypeControlDictionary
}
// Bytes serializes the entry.
func (data ControlDictionaryEntryData) Bytes() []byte {
return compression.PackControlWords(data.Words)
}