mirror of
https://github.com/IllusionMan1212/avif-odin.git
synced 2026-10-24 10:12:28 +00:00
initial
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
package avif
|
||||
|
||||
import "core:encoding/endian"
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
BOX_HEADER_SIZE :: 8 // 4 for box size, 4 for box type
|
||||
|
||||
_BoxError :: enum {
|
||||
ReadExceedsBox,
|
||||
}
|
||||
|
||||
BoxType :: enum u32 {
|
||||
FTYP = 'f' << 24 | 't' << 16 | 'y' << 8 | 'p', // File Type
|
||||
MDAT = 'm' << 24 | 'd' << 16 | 'a' << 8 | 't', // Media Data
|
||||
META = 'm' << 24 | 'e' << 16 | 't' << 8 | 'a', // Metadata
|
||||
HDLR = 'h' << 24 | 'd' << 16 | 'l' << 8 | 'r', // Declares Metadata Handler Type
|
||||
ILOC = 'i' << 24 | 'l' << 16 | 'o' << 8 | 'c', // Item Location
|
||||
IINF = 'i' << 24 | 'i' << 16 | 'n' << 8 | 'f', // Item Information
|
||||
INFE = 'i' << 24 | 'n' << 16 | 'f' << 8 | 'e', // Item Info Entry
|
||||
PITM = 'p' << 24 | 'i' << 16 | 't' << 8 | 'm', // Primary Item Reference
|
||||
IPRP = 'i' << 24 | 'p' << 16 | 'r' << 8 | 'p', // Item Properties
|
||||
IREF = 'i' << 24 | 'r' << 16 | 'e' << 8 | 'f', // Item Reference
|
||||
GRPL = 'g' << 24 | 'r' << 16 | 'p' << 8 | 'l', // Group List
|
||||
IPCO = 'i' << 24 | 'p' << 16 | 'c' << 8 | 'o', // Item Property Container
|
||||
ISPE = 'i' << 24 | 's' << 16 | 'p' << 8 | 'e', // Image Spatial Extents
|
||||
PIXI = 'p' << 24 | 'i' << 16 | 'x' << 8 | 'i', // Pixel Information
|
||||
COLR = 'c' << 24 | 'o' << 16 | 'l' << 8 | 'r', // Color Information
|
||||
AV1C = 'a' << 24 | 'v' << 16 | '1' << 8 | 'C', // AV1 Codec Configuration
|
||||
IPMA = 'i' << 24 | 'p' << 16 | 'm' << 8 | 'a', // Item Property Association
|
||||
CLLI = 'c' << 24 | 'l' << 16 | 'l' << 8 | 'i', // Content Light Level Info
|
||||
}
|
||||
|
||||
BoxError :: union {
|
||||
io.Error,
|
||||
_BoxError,
|
||||
}
|
||||
|
||||
Box :: struct {
|
||||
size: u32,
|
||||
type: BoxType,
|
||||
}
|
||||
|
||||
Reader :: struct {
|
||||
using current_box: Box,
|
||||
s: []byte, // read-only buffer
|
||||
i: i64, // current reading index
|
||||
box_pos: i64, // Byte index for the Box
|
||||
}
|
||||
|
||||
reader_init :: proc(r: ^Reader, s: []byte) {
|
||||
r.s = s
|
||||
r.i = 0
|
||||
r.box_pos = 0
|
||||
}
|
||||
|
||||
read_header :: proc(r: ^Reader) -> (err: BoxError) {
|
||||
r.box_pos = 0
|
||||
r.size = read_u32be(r) or_return
|
||||
type := read_u32be(r) or_return
|
||||
r.type = transmute(BoxType)type
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
read_byte :: proc(r: ^Reader) -> (byte, BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
if r.box_pos >= i64(r.size) {
|
||||
return 0, .ReadExceedsBox
|
||||
}
|
||||
b := r.s[r.i]
|
||||
r.i += 1
|
||||
r.box_pos += 1
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_u16be :: proc(r: ^Reader) -> (u16, BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
if r.box_pos + 2 > i64(r.size) {
|
||||
return 0, .ReadExceedsBox
|
||||
}
|
||||
b := endian.unchecked_get_u16be(r.s[r.i:])
|
||||
r.i += 2
|
||||
r.box_pos += 2
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_u32be :: proc(r: ^Reader) -> (u32, BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
if r.size != 0 && r.box_pos + 4 > i64(r.size) {
|
||||
return 0, .ReadExceedsBox
|
||||
}
|
||||
b := endian.unchecked_get_u32be(r.s[r.i:])
|
||||
r.i += 4
|
||||
r.box_pos += 4
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_u64be :: proc(r: ^Reader) -> (u64, BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
if r.size != 0 && r.box_pos + 8 > i64(r.size) {
|
||||
return 0, .ReadExceedsBox
|
||||
}
|
||||
b := endian.unchecked_get_u64be(r.s[r.i:])
|
||||
r.i += 8
|
||||
r.box_pos += 8
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_slice :: proc(r: ^Reader, s: []byte) -> (n: int, err: BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
n = copy(s, r.s[r.i:])
|
||||
if r.box_pos + i64(n) > i64(r.size) {
|
||||
return 0, .ReadExceedsBox
|
||||
}
|
||||
r.i += i64(n)
|
||||
r.box_pos += i64(n)
|
||||
return
|
||||
}
|
||||
|
||||
read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, 0, .EOF
|
||||
}
|
||||
if c := r.s[r.i]; c < utf8.RUNE_SELF {
|
||||
if r.box_pos >= i64(r.size) {
|
||||
return 0, 0, .ReadExceedsBox
|
||||
}
|
||||
r.i += 1
|
||||
r.box_pos += 1
|
||||
return rune(c), 1, nil
|
||||
}
|
||||
ch, size = utf8.decode_rune(r.s[r.i:])
|
||||
if r.box_pos + i64(size) > i64(r.size) {
|
||||
return 0, 0, .ReadExceedsBox
|
||||
}
|
||||
r.i += i64(size)
|
||||
r.box_pos += i64(size)
|
||||
return
|
||||
}
|
||||
|
||||
read_string :: proc(r: ^Reader) -> (str: string, err: BoxError) {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return "", .EOF
|
||||
}
|
||||
|
||||
sb: strings.Builder
|
||||
strings.builder_init_len_cap(&sb, 0, 8)
|
||||
defer strings.builder_destroy(&sb)
|
||||
|
||||
for {
|
||||
rune, _ := read_rune(r) or_break
|
||||
if rune == '\x00' {
|
||||
break
|
||||
}
|
||||
|
||||
strings.write_rune(&sb, rune)
|
||||
}
|
||||
|
||||
return strings.clone(strings.to_string(sb)), err
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
read_bitfield_u32 :: proc(r: ^Reader, $T: typeid) -> (T, BoxError) where size_of(T) == 4 {
|
||||
b, err := read_u32be(r)
|
||||
return T(b), err
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
read_bitfield_u16 :: proc(r: ^Reader, $T: typeid) -> (T, BoxError) where size_of(T) == 2 {
|
||||
b, err := read_u16be(r)
|
||||
return T(b), err
|
||||
}
|
||||
|
||||
read_bitfield :: proc {
|
||||
read_bitfield_u16,
|
||||
read_bitfield_u32,
|
||||
}
|
||||
|
||||
skip_box :: proc(r: ^Reader) {
|
||||
fmt.printfln("SKIPPED! %v with size %d", r.type, r.size)
|
||||
reader_seek(r, auto_cast r.size - BOX_HEADER_SIZE, .Current)
|
||||
}
|
||||
|
||||
remaining_box_size :: proc(r: ^Reader) -> i64 {
|
||||
return i64(r.size) - r.box_pos
|
||||
}
|
||||
|
||||
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, BoxError) {
|
||||
abs: i64
|
||||
switch whence {
|
||||
case .Start:
|
||||
abs = offset
|
||||
case .Current:
|
||||
abs = r.i + offset
|
||||
case .End:
|
||||
abs = i64(len(r.s)) + offset
|
||||
case:
|
||||
return 0, .Invalid_Whence
|
||||
}
|
||||
|
||||
if abs < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
r.i = abs
|
||||
return abs, nil
|
||||
}
|
||||
Reference in New Issue
Block a user