├── go.mod ├── ffv1 ├── rangecoder │ ├── util.go │ ├── tables.go │ └── range.go ├── golomb │ ├── tables.go │ ├── util.go │ ├── bitreader.go │ └── golomb.go ├── constants.go ├── genhbd ├── pred16.go ├── pred32.go ├── jpeg2000rct.go ├── pred.go ├── crc32mpeg2.go ├── record.go ├── api.go └── slice.go ├── COPYING └── README.md /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dwbuiten/go-ffv1 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /ffv1/rangecoder/util.go: -------------------------------------------------------------------------------- 1 | package rangecoder 2 | 3 | func min32(a int32, b int32) int32 { 4 | if a > b { 5 | return b 6 | } 7 | return a 8 | } 9 | -------------------------------------------------------------------------------- /ffv1/golomb/tables.go: -------------------------------------------------------------------------------- 1 | package golomb 2 | 3 | // Section 3.8.2.2.1. Run Length Coding 4 | var log2_run = [41]uint8{ 5 | 0, 0, 0, 0, 1, 1, 1, 1, 6 | 2, 2, 2, 2, 3, 3, 3, 3, 7 | 4, 4, 5, 5, 6, 6, 7, 7, 8 | 8, 9, 10, 11, 12, 13, 14, 15, 9 | 16, 17, 18, 19, 20, 21, 22, 23, 10 | 24, 11 | } 12 | -------------------------------------------------------------------------------- /ffv1/golomb/util.go: -------------------------------------------------------------------------------- 1 | package golomb 2 | 3 | func min32(a int32, b int32) int32 { 4 | if a > b { 5 | return b 6 | } 7 | return a 8 | } 9 | 10 | func max32(a int32, b int32) int32 { 11 | if a < b { 12 | return b 13 | } 14 | return a 15 | } 16 | 17 | func abs32(n int32) int32 { 18 | if n >= 0 { 19 | return n 20 | } 21 | return -1 * n 22 | } 23 | -------------------------------------------------------------------------------- /ffv1/constants.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | // Internal constants. 4 | const ( 5 | maxQuantTables = 8 // Only defined in FFmpeg? 6 | maxContextInputs = 5 // 4.9. Quantization Table Set 7 | contextSize = 32 // 4.1. Parameters 8 | ) 9 | 10 | // API constants. 11 | 12 | // Colorspaces. 13 | // From 4.1.5. colorspace_type 14 | const ( 15 | YCbCr = 0 16 | RGB = 1 17 | ) 18 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Derek Buitenhuis 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /ffv1/golomb/bitreader.go: -------------------------------------------------------------------------------- 1 | package golomb 2 | 3 | type bitReader struct { 4 | buf []byte 5 | pos int 6 | bitBuf uint32 7 | bitsInBuf uint32 8 | } 9 | 10 | // Creates a new bitreader. 11 | func newBitReader(buf []byte) (r *bitReader) { 12 | ret := new(bitReader) 13 | ret.buf = buf 14 | return ret 15 | } 16 | 17 | // Reads 'count' bits, up to 32. 18 | func (r *bitReader) u(count uint32) (result uint32) { 19 | if count > 32 { 20 | panic("WTF more than 32 bits") 21 | } 22 | for count > r.bitsInBuf { 23 | r.bitBuf <<= 8 24 | r.bitBuf |= uint32(r.buf[r.pos]) 25 | r.bitsInBuf += 8 26 | r.pos++ 27 | 28 | if r.bitsInBuf > 24 { 29 | if count <= r.bitsInBuf { 30 | break 31 | } 32 | if count <= 32 { 33 | return r.u(16)<<16 | r.u(count-16) 34 | } 35 | } 36 | } 37 | r.bitsInBuf -= count 38 | return (r.bitBuf >> r.bitsInBuf) & ((uint32(1) << count) - 1) 39 | } 40 | -------------------------------------------------------------------------------- /ffv1/genhbd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Simple code gen tool to make a 16 and 32 bit person of deriveBorders. 4 | # In theory, I could have just used an interface, but that's just 5 | # ugly in a different way. 6 | 7 | use strict; 8 | use warnings; 9 | 10 | my $bitdepth = shift; 11 | 12 | open(my $if, "<", "pred.go") || die("cannot open pred.go for reading"); 13 | open(my $of, ">", "pred$bitdepth.go") || die("cannot open pred$bitdepth.go for writing"); 14 | 15 | print $of "package ffv1\n\n"; 16 | print $of "// This file is automatically generated from pred.go using go generate\n"; 17 | print $of "// Please DO NOT manually modify this file\n\n"; 18 | 19 | my $started = 0; 20 | while (<$if>) { 21 | if (/deriveBorders/) { 22 | s/deriveBorders/deriveBorders$bitdepth/; 23 | s/uint8/uint$bitdepth/; 24 | print $of $_; 25 | $started = 1; 26 | next; 27 | } 28 | if ($started == 0) { 29 | next; 30 | } 31 | if (/^}/) { 32 | print $of $_; 33 | last; 34 | } 35 | print $of $_; 36 | } 37 | 38 | close($if); 39 | close($of); 40 | -------------------------------------------------------------------------------- /ffv1/rangecoder/tables.go: -------------------------------------------------------------------------------- 1 | package rangecoder 2 | 3 | // 3.8.1.5. default_state_transition 4 | var DefaultStateTransition = [256]uint8{ 5 | 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 6 | 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 7 | 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 8 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 9 | 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 10 | 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 11 | 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 12 | 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 13 | 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 14 | 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 15 | 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 16 | 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 17 | 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 18 | 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 19 | 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 20 | 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0, 21 | } 22 | -------------------------------------------------------------------------------- /ffv1/pred16.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | // This file is automatically generated from pred.go using go generate 4 | // Please DO NOT manually modify this file 5 | 6 | func deriveBorders16(plane []uint16, x int, y int, width int, height int, stride int) (int, int, int, int, int, int) { 7 | var T int 8 | var L int 9 | var t int 10 | var l int 11 | var tr int 12 | var tl int 13 | 14 | pos := y*stride + x 15 | 16 | // This is really slow and stupid but matches the spec exactly. Each of the 17 | // neighbouring values has been left entirely separate, and none skipped, 18 | // even if they could be. 19 | // 20 | // Please never implement an actual decoder this way. 21 | 22 | // T 23 | if y > 1 { 24 | T = int(plane[pos-(2*stride)]) 25 | } 26 | 27 | // L 28 | if y > 0 && x == 1 { 29 | L = int(plane[pos-stride-1]) 30 | } else if x > 1 { 31 | L = int(plane[pos-2]) 32 | } 33 | 34 | // t 35 | if y > 0 { 36 | t = int(plane[pos-stride]) 37 | } 38 | 39 | // l 40 | if x > 0 { 41 | l = int(plane[pos-1]) 42 | } else if y > 0 { 43 | l = int(plane[pos-stride]) 44 | } 45 | 46 | // tl 47 | if y > 1 && x == 0 { 48 | tl = int(plane[pos-(2*stride)]) 49 | } else if y > 0 && x > 0 { 50 | tl = int(plane[pos-stride-1]) 51 | } 52 | 53 | // tr 54 | if y > 0 { 55 | tr = int(plane[pos-stride+min(1, width-1-x)]) 56 | } 57 | 58 | return T, L, t, l, tr, tl 59 | } 60 | -------------------------------------------------------------------------------- /ffv1/pred32.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | // This file is automatically generated from pred.go using go generate 4 | // Please DO NOT manually modify this file 5 | 6 | func deriveBorders32(plane []uint32, x int, y int, width int, height int, stride int) (int, int, int, int, int, int) { 7 | var T int 8 | var L int 9 | var t int 10 | var l int 11 | var tr int 12 | var tl int 13 | 14 | pos := y*stride + x 15 | 16 | // This is really slow and stupid but matches the spec exactly. Each of the 17 | // neighbouring values has been left entirely separate, and none skipped, 18 | // even if they could be. 19 | // 20 | // Please never implement an actual decoder this way. 21 | 22 | // T 23 | if y > 1 { 24 | T = int(plane[pos-(2*stride)]) 25 | } 26 | 27 | // L 28 | if y > 0 && x == 1 { 29 | L = int(plane[pos-stride-1]) 30 | } else if x > 1 { 31 | L = int(plane[pos-2]) 32 | } 33 | 34 | // t 35 | if y > 0 { 36 | t = int(plane[pos-stride]) 37 | } 38 | 39 | // l 40 | if x > 0 { 41 | l = int(plane[pos-1]) 42 | } else if y > 0 { 43 | l = int(plane[pos-stride]) 44 | } 45 | 46 | // tl 47 | if y > 1 && x == 0 { 48 | tl = int(plane[pos-(2*stride)]) 49 | } else if y > 0 && x > 0 { 50 | tl = int(plane[pos-stride-1]) 51 | } 52 | 53 | // tr 54 | if y > 0 { 55 | tr = int(plane[pos-stride+min(1, width-1-x)]) 56 | } 57 | 58 | return T, L, t, l, tr, tl 59 | } 60 | -------------------------------------------------------------------------------- /ffv1/jpeg2000rct.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | // Converts one line from 9-bit JPEG2000-RCT to planar GBR. 4 | // 5 | // See: 3.7.2. RGB 6 | func rct8(dst [][]byte, src [][]uint16, w int, h int, stride int, offset int) { 7 | Y := src[0][offset:] 8 | Cb := src[1][offset:] 9 | Cr := src[2][offset:] 10 | G := dst[0][offset:] 11 | B := dst[1][offset:] 12 | R := dst[2][offset:] 13 | for y := 0; y < h; y++ { 14 | for x := 0; x < w; x++ { 15 | Cbtmp := int32(Cb[(y*stride)+x]) - (1 << 8) // Missing from spec 16 | Crtmp := int32(Cr[(y*stride)+x]) - (1 << 8) // Missing from spec 17 | g := int32(Y[(y*stride)+x]) - ((int32(Cbtmp) + int32(Crtmp)) >> 2) 18 | r := int32(Crtmp) + g 19 | b := int32(Cbtmp) + g 20 | G[(y*stride)+x] = byte(g) 21 | B[(y*stride)+x] = byte(b) 22 | R[(y*stride)+x] = byte(r) 23 | } 24 | } 25 | if len(src) == 4 { 26 | s := src[3][offset:] 27 | d := dst[3][offset:] 28 | for y := 0; y < h; y++ { 29 | for x := 0; x < w; x++ { 30 | d[(y*stride)+x] = byte(s[(y*stride)+x]) 31 | } 32 | } 33 | } 34 | } 35 | 36 | // Converts one line from 10 to 16 bit JPEG2000-RCT to planar GBR, in place. 37 | // 38 | // See: 3.7.2. RGB 39 | func rctMid(src [][]uint16, w int, h int, stride int, offset int, bits uint) { 40 | Y := src[0][offset:] 41 | Cb := src[1][offset:] 42 | Cr := src[2][offset:] 43 | for y := 0; y < h; y++ { 44 | for x := 0; x < w; x++ { 45 | Cbtmp := int32(Cb[(y*stride)+x]) - int32(1<> 2) 48 | r := int32(Crtmp) + b 49 | g := int32(Cbtmp) + b 50 | Y[(y*stride)+x] = uint16(g) 51 | Cb[(y*stride)+x] = uint16(b) 52 | Cr[(y*stride)+x] = uint16(r) 53 | } 54 | } 55 | } 56 | 57 | // Converts one line from 17-bit JPEG2000-RCT to planar GBR, in place. 58 | // 59 | // Currently unused until I refactor and allow for 17-bit buffers. 60 | // 61 | // See: 3.7.2. RGB 62 | func rct16(dst [][]uint16, src [][]uint32, w int, h int, stride int, offset int) { 63 | Y := src[0][offset:] 64 | Cb := src[1][offset:] 65 | Cr := src[2][offset:] 66 | G := dst[0][offset:] 67 | B := dst[1][offset:] 68 | R := dst[2][offset:] 69 | for y := 0; y < h; y++ { 70 | for x := 0; x < w; x++ { 71 | Cbtmp := int32(Cb[(y*stride)+x]) - (1 << 16) // Missing from spec 72 | Crtmp := int32(Cr[(y*stride)+x]) - (1 << 16) // Missing from spec 73 | g := int32(Y[(y*stride)+x]) - ((int32(Cbtmp) + int32(Crtmp)) >> 2) 74 | r := int32(Crtmp) + g 75 | b := int32(Cbtmp) + g 76 | G[(y*stride)+x] = uint16(g) 77 | B[(y*stride)+x] = uint16(b) 78 | R[(y*stride)+x] = uint16(r) 79 | } 80 | } 81 | if len(src) == 4 { 82 | s := src[3][offset:] 83 | d := dst[3][offset:] 84 | for y := 0; y < h; y++ { 85 | for x := 0; x < w; x++ { 86 | d[(y*stride)+x] = uint16(s[(y*stride)+x]) 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ffv1/pred.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | // This file is used as a template for pred16.go (high bit depth median prediction) 4 | // Please run 'go generate' if you modify the following function. 5 | // 6 | //go:generate ./genhbd 16 7 | //go:generate ./genhbd 32 8 | 9 | // Calculates all the neighbouring pixel values given: 10 | // 11 | // +---+---+---+---+ 12 | // | | | T | | 13 | // +---+---+---+---+ 14 | // | |tl | t |tr | 15 | // +---+---+---+---+ 16 | // | L | l | X | | 17 | // +---+---+---+---+ 18 | // 19 | // where 'X' is the pixel at our current position, and borders are: 20 | // 21 | // +---+---+---+---+---+---+---+---+ 22 | // | 0 | 0 | | 0 | 0 | 0 | | 0 | 23 | // +---+---+---+---+---+---+---+---+ 24 | // | 0 | 0 | | 0 | 0 | 0 | | 0 | 25 | // +---+---+---+---+---+---+---+---+ 26 | // | | | | | | | | | 27 | // +---+---+---+---+---+---+---+---+ 28 | // | 0 | 0 | | a | b | c | | c | 29 | // +---+---+---+---+---+---+---+---+ 30 | // | 0 | a | | d | e | f | | f | 31 | // +---+---+---+---+---+---+---+---+ 32 | // | 0 | d | | g | h | i | | i | 33 | // +---+---+---+---+---+---+---+---+ 34 | // 35 | // where 'a' through 'i' are pixel values in a plane. 36 | // 37 | // See: * 3.1. Border 38 | // * 3.2. Samples 39 | func deriveBorders(plane []uint8, x int, y int, width int, height int, stride int) (int, int, int, int, int, int) { 40 | var T int 41 | var L int 42 | var t int 43 | var l int 44 | var tr int 45 | var tl int 46 | 47 | pos := y*stride + x 48 | 49 | // This is really slow and stupid but matches the spec exactly. Each of the 50 | // neighbouring values has been left entirely separate, and none skipped, 51 | // even if they could be. 52 | // 53 | // Please never implement an actual decoder this way. 54 | 55 | // T 56 | if y > 1 { 57 | T = int(plane[pos-(2*stride)]) 58 | } 59 | 60 | // L 61 | if y > 0 && x == 1 { 62 | L = int(plane[pos-stride-1]) 63 | } else if x > 1 { 64 | L = int(plane[pos-2]) 65 | } 66 | 67 | // t 68 | if y > 0 { 69 | t = int(plane[pos-stride]) 70 | } 71 | 72 | // l 73 | if x > 0 { 74 | l = int(plane[pos-1]) 75 | } else if y > 0 { 76 | l = int(plane[pos-stride]) 77 | } 78 | 79 | // tl 80 | if y > 1 && x == 0 { 81 | tl = int(plane[pos-(2*stride)]) 82 | } else if y > 0 && x > 0 { 83 | tl = int(plane[pos-stride-1]) 84 | } 85 | 86 | // tr 87 | if y > 0 { 88 | tr = int(plane[pos-stride+min(1, width-1-x)]) 89 | } 90 | 91 | return T, L, t, l, tr, tl 92 | } 93 | 94 | // Given the neighbouring pixel values, calculate the context. 95 | // 96 | // See: * 3.4. Context 97 | // * 3.5. Quantization Table Sets 98 | func getContext(quant_tables [5][256]int16, T int, L int, t int, l int, tr int, tl int) int32 { 99 | return int32(quant_tables[0][(l-tl)&255]) + 100 | int32(quant_tables[1][(tl-t)&255]) + 101 | int32(quant_tables[2][(t-tr)&255]) + 102 | int32(quant_tables[3][(L-l)&255]) + 103 | int32(quant_tables[4][(T-t)&255]) 104 | } 105 | 106 | func min(a int, b int) int { 107 | if a < b { 108 | return a 109 | } 110 | return b 111 | } 112 | 113 | func max(a int, b int) int { 114 | if a > b { 115 | return a 116 | } 117 | return b 118 | } 119 | 120 | // Calculate the median value of 3 numbers 121 | // 122 | // See: 2.2.5. Mathematical Functions 123 | func getMedian(a int, b int, c int) int { 124 | return a + b + c - min(a, min(b, c)) - max(a, max(b, c)) 125 | } 126 | -------------------------------------------------------------------------------- /ffv1/crc32mpeg2.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | import ( 4 | "hash/crc32" 5 | ) 6 | 7 | // Table for ISO/IEC 13818-1 CRC-32/MPEG-2 8 | var crc32table = &crc32.Table{ 9 | 0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517, 10 | 0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B, 11 | 0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048, 12 | 0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652, 13 | 0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D, 14 | 0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095, 15 | 0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA, 16 | 0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0, 17 | 0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3, 18 | 0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF, 19 | 0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730, 20 | 0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A, 21 | 0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05, 22 | 0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475, 23 | 0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A, 24 | 0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840, 25 | 0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB, 26 | 0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87, 27 | 0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4, 28 | 0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE, 29 | 0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1, 30 | 0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64, 31 | 0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B, 32 | 0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351, 33 | 0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832, 34 | 0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E, 35 | 0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5, 36 | 0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF, 37 | 0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0, 38 | 0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0, 39 | 0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F, 40 | 0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185, 41 | 0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A, 42 | 0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176, 43 | 0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15, 44 | 0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F, 45 | 0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620, 46 | 0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8, 47 | 0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7, 48 | 0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD, 49 | 0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E, 50 | 0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2, 51 | 0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1, 52 | } 53 | 54 | // Go's CRC32 package always does pre- and post-inversion, so we have to compensate 55 | // for that here. 56 | // 57 | // See: 4.8.3. slice_crc_parity 58 | func crc32MPEG2(buf []byte) uint32 { 59 | return ^crc32.Update(^uint32(0), crc32table, buf) 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FFV1 Decoder in Go 2 | --- 3 | 4 | This repo contains an FFV1 Version 3 decoder implemented from draft-ietf-cellar-ffv1. 5 | 6 | The reason for this project was to test how good the specification was, and indeed, during 7 | the development of this, several issues were unearthed. The secondary goal was to write a 8 | readable, commented, good reference; obviousness and spec-similarity over speed, struct 9 | members that match the spec, etc. 10 | 11 | ... Well, at least the former goal was met. 12 | 13 | As such, there's a lot of non-idiomatic Go in here, and a lot of gross argument passing 14 | that should be refactored out into the contexts, stuff that should be interfaces instead 15 | of code generation etc... one day. Any day now. If we keep waiting, it may happen. Surely. 16 | 17 | TODO 18 | --- 19 | 20 | * Fix Alpha Support 21 | 22 | API 23 | --- 24 | 25 | You can read the API godoc at [godoc.org/github.com/dwbuiten/go-ffv1/ffv1](https://godoc.org/github.com/dwbuiten/go-ffv1/ffv1). 26 | 27 | Example of Decoding FFV1 in Matroska 28 | --- 29 | 30 | ```Go 31 | package main 32 | 33 | import ( 34 | "encoding/binary" 35 | "fmt" 36 | "io" 37 | "log" 38 | "os" 39 | "strings" 40 | 41 | "github.com/dwbuiten/go-ffv1/ffv1" 42 | "github.com/dwbuiten/matroska" 43 | ) 44 | 45 | func main() { 46 | f, err := os.Open("input.mkv") 47 | if err != nil { 48 | log.Fatalln(err) 49 | } 50 | defer f.Close() 51 | 52 | mat, err := matroska.NewDemuxer(f) 53 | if err != nil { 54 | log.Fatalln(err) 55 | } 56 | defer mat.Close() 57 | 58 | // Assuming track 0 is video because lazy. 59 | ti, err := mat.GetTrackInfo(0) 60 | if err != nil { 61 | log.Fatalln(err) 62 | } 63 | 64 | fmt.Printf("Encode is %dx%d\n", ti.Video.PixelWidth, ti.Video.PixelHeight) 65 | 66 | extradata := ti.CodecPrivate 67 | if strings.Contains(ti.CodecID, "VFW") { 68 | extradata = extradata[40:] // As per Matroska spec for VFW CodecPrivate 69 | } 70 | 71 | d, err := ffv1.NewDecoder(extradata, ti.Video.PixelWidth, ti.Video.PixelHeight) 72 | if err != nil { 73 | log.Fatalln(err) 74 | } 75 | 76 | file, err := os.Create("test.raw") 77 | if err != nil { 78 | log.Fatalln(err) 79 | } 80 | defer file.Close() 81 | 82 | for { 83 | packet, err := mat.ReadPacket() 84 | if err == io.EOF { 85 | break 86 | } else if err != nil { 87 | log.Fatalln(err) 88 | } 89 | 90 | fmt.Printf("extradata = %d packet = %d track = %d\n", len(extradata), len(packet.Data), packet.Track) 91 | if packet.Track != 0 { 92 | continue 93 | } 94 | 95 | frame, err := d.DecodeFrame(packet.Data) 96 | if err != nil { 97 | log.Fatalln(err) 98 | } 99 | fmt.Printf("Frame decoded at %dx%d\n", frame.Width, frame.Height) 100 | 101 | if frame.BitDepth == 8 { 102 | err = binary.Write(file, binary.LittleEndian, frame.Buf[0]) 103 | if err != nil { 104 | log.Fatalln(err) 105 | } 106 | err = binary.Write(file, binary.LittleEndian, frame.Buf[1]) 107 | if err != nil { 108 | log.Fatalln(err) 109 | } 110 | err = binary.Write(file, binary.LittleEndian, frame.Buf[2]) 111 | if err != nil { 112 | log.Fatalln(err) 113 | } 114 | } else { 115 | err = binary.Write(file, binary.LittleEndian, frame.Buf16[0]) 116 | if err != nil { 117 | log.Fatalln(err) 118 | } 119 | err = binary.Write(file, binary.LittleEndian, frame.Buf16[1]) 120 | if err != nil { 121 | log.Fatalln(err) 122 | } 123 | err = binary.Write(file, binary.LittleEndian, frame.Buf16[2]) 124 | if err != nil { 125 | log.Fatalln(err) 126 | } 127 | } 128 | } 129 | fmt.Println("Done.") 130 | } 131 | ``` 132 | -------------------------------------------------------------------------------- /ffv1/rangecoder/range.go: -------------------------------------------------------------------------------- 1 | // Package rangecoer implements a range coder as per 3.8.1. Range Coding Mode 2 | // of draft-ietf-cellar-ffv1. 3 | package rangecoder 4 | 5 | // Cross-references are to 6 | // https://tools.ietf.org/id/draft-ietf-cellar-ffv1-17 7 | 8 | // Coder is an instance of a range coder, as defined in: 9 | // Martin, G. Nigel N., "Range encoding: an algorithm for 10 | // removing redundancy from a digitised message.", July 1979. 11 | type Coder struct { 12 | buf []byte 13 | pos int 14 | low uint16 15 | rng uint16 16 | cur_byte int32 17 | zero_state [256]uint8 18 | one_state [256]uint8 19 | } 20 | 21 | // NewCoder creates a new range coder instance. 22 | // 23 | // See: 3.8.1. Range Coding Mode 24 | func NewCoder(buf []byte) *Coder { 25 | ret := new(Coder) 26 | 27 | ret.buf = buf 28 | // Figure 15. 29 | ret.pos = 2 30 | // Figure 14. 31 | ret.low = uint16(buf[0])<<8 | uint16(buf[1]) 32 | // Figure 13. 33 | ret.rng = 0xFF00 34 | ret.cur_byte = -1 35 | if ret.low >= ret.rng { 36 | ret.low = ret.rng 37 | ret.pos = len(buf) - 1 38 | } 39 | 40 | // 3.8.1.3. Initial Values for the Context Model 41 | ret.SetTable(DefaultStateTransition) 42 | 43 | return ret 44 | } 45 | 46 | // Refills the buffer 47 | func (c *Coder) refill() { 48 | // Figure 12. 49 | if c.rng < 0x100 { 50 | c.rng = c.rng << 8 51 | c.low = c.low << 8 52 | if c.pos < len(c.buf) { 53 | c.low += uint16(c.buf[c.pos]) 54 | c.pos++ 55 | } 56 | } 57 | } 58 | 59 | // Gets the next boolean state 60 | func (c *Coder) get(state *uint8) bool { 61 | // Figure 10. 62 | rangeoff := uint16((uint32(c.rng) * uint32((*state))) >> 8) 63 | c.rng -= rangeoff 64 | if c.low < c.rng { 65 | *state = c.zero_state[int(*state)] 66 | c.refill() 67 | return false 68 | } else { 69 | c.low -= c.rng 70 | *state = c.one_state[int(*state)] 71 | c.rng = rangeoff 72 | c.refill() 73 | return true 74 | } 75 | } 76 | 77 | // UR gets the next range coded unsigned scalar symbol. 78 | // 79 | // See: 4. Bitstream 80 | func (c *Coder) UR(state []uint8) uint32 { 81 | return uint32(c.symbol(state, false)) 82 | } 83 | 84 | // SR gets the next range coded signed scalar symbol. 85 | // 86 | // See: 4. Bitstream 87 | func (c *Coder) SR(state []uint8) int32 { 88 | return c.symbol(state, true) 89 | } 90 | 91 | // BR gets the next range coded Boolean symbol. 92 | // 93 | // See: 4. Bitstream 94 | func (c *Coder) BR(state []uint8) bool { 95 | return c.get(&state[0]) 96 | } 97 | 98 | // Gets the next range coded symbol. 99 | // 100 | // See: 3.8.1.2. Range Non Binary Values 101 | func (c *Coder) symbol(state []uint8, signed bool) int32 { 102 | if c.get(&state[0]) { 103 | return 0 104 | } 105 | 106 | e := int32(0) 107 | for c.get(&state[1+min32(e, 9)]) { 108 | e++ 109 | if e > 31 { 110 | panic("WTF range coder!") 111 | } 112 | } 113 | 114 | a := uint32(1) 115 | for i := e - 1; i >= 0; i-- { 116 | a = a * 2 117 | if c.get(&state[22+min32(i, 9)]) { 118 | a++ 119 | } 120 | } 121 | 122 | if signed && c.get(&state[11+min32(e, 10)]) { 123 | return -(int32(a)) 124 | } else { 125 | return int32(a) 126 | } 127 | } 128 | 129 | func (c *Coder) SetTable(table [256]uint8) { 130 | // 3.8.1.4. State Transition Table 131 | 132 | // Figure 17. 133 | for i := 0; i < 256; i++ { 134 | c.one_state[i] = table[i] 135 | } 136 | // Figure 18. 137 | for i := 1; i < 255; i++ { 138 | c.zero_state[i] = uint8(uint16(256) - uint16(c.one_state[256-i])) 139 | } 140 | } 141 | 142 | // SentinalEnd ends the current range coder. 143 | // 144 | // See: 3.8.1.1.1. Termination 145 | // * Sentinal Mode 146 | func (c *Coder) SentinalEnd() { 147 | state := uint8(129) 148 | c.get(&state) 149 | } 150 | 151 | // GetPos gets the current position in the bitstream. 152 | func (c *Coder) GetPos() int { 153 | if c.rng < 0x100 { 154 | return c.pos - 1 155 | } 156 | return c.pos 157 | } 158 | -------------------------------------------------------------------------------- /ffv1/golomb/golomb.go: -------------------------------------------------------------------------------- 1 | // Package golomb implements a Golomb-Rice coder as per Section 3.8.2. Golomb Rice Mode 2 | // of draft-ietf-cellar-ffv1. 3 | package golomb 4 | 5 | // Coder is an instance of a Golomb-Rice coder as described in 3.8.2. Golomb Rice Mode. 6 | type Coder struct { 7 | r *bitReader 8 | run_mode int 9 | run_count int 10 | run_index int 11 | x uint32 12 | w uint32 13 | } 14 | 15 | // State contains a single set of states for the a Golomb-Rice coder as define in 16 | // 3.8.2.4. Initial Values for the VLC context state. 17 | type State struct { 18 | drift int32 19 | error_sum int32 20 | bias int32 21 | count int32 22 | } 23 | 24 | // NewState creates a Golomb-Rice state with the initial values defined in 25 | // 3.8.2.4. Initial Values for the VLC context state. 26 | func NewState() State { 27 | return State{ 28 | drift: 0, 29 | error_sum: 4, 30 | bias: 0, 31 | count: 1, 32 | } 33 | } 34 | 35 | // NewCoder creates a new Golomb-Rice coder. 36 | func NewCoder(buf []byte) *Coder { 37 | ret := new(Coder) 38 | ret.r = newBitReader(buf) 39 | return ret 40 | } 41 | 42 | // NewPlane should be called on a given Coder as each new Plane is 43 | // processed. It resets the run index and sets the slice width. 44 | // 45 | // See: 3.8.2.2.1. Run Length Coding 46 | func (c *Coder) NewPlane(width uint32) { 47 | c.w = width 48 | c.run_index = 0 49 | } 50 | 51 | // Starts a new run. 52 | func (c *Coder) newRun() { 53 | c.run_mode = 0 54 | c.run_count = 0 55 | } 56 | 57 | // NewLine resets the x position and starts a new run, 58 | // since runs can only be per-line. 59 | func (c *Coder) NewLine() { 60 | c.newRun() 61 | c.x = 0 62 | } 63 | 64 | // SG gets the next Golomb-Rice coded signed scalar symbol. 65 | // 66 | // See: * 3.8.2. Golomb Rice Mode 67 | // * 4. Bitstream 68 | func (c *Coder) SG(context int32, state *State, bits uint) int32 { 69 | // Section 3.8.2.2. Run Mode 70 | if context == 0 && c.run_mode == 0 { 71 | c.run_mode = 1 72 | } 73 | 74 | // Section 3.8.2.2.1. Run Length Coding 75 | if c.run_mode != 0 { 76 | if c.run_count == 0 && c.run_mode == 1 { 77 | if c.r.u(1) == 1 { 78 | c.run_count = 1 << log2_run[c.run_index] 79 | if c.x+uint32(c.run_count) <= c.w { 80 | c.run_index++ 81 | } 82 | } else { 83 | if log2_run[c.run_index] != 0 { 84 | c.run_count = int(c.r.u(uint32(log2_run[c.run_index]))) 85 | } else { 86 | c.run_count = 0 87 | } 88 | if c.run_index != 0 { 89 | c.run_index-- 90 | } 91 | // This is in the spec but how it works is... non-obvious. 92 | c.run_mode = 2 93 | } 94 | } 95 | 96 | c.run_count-- 97 | // No more repeats; the run is over. Read a new symbol. 98 | if c.run_count < 0 { 99 | c.newRun() 100 | diff := c.get_vlc_symbol(state, bits) 101 | // 3.8.2.2.2. Level Coding 102 | if diff >= 0 { 103 | diff++ 104 | } 105 | c.x++ 106 | return diff 107 | } else { 108 | // The run is still going; return a difference of zero. 109 | c.x++ 110 | return 0 111 | } 112 | } else { 113 | // We aren't in run mode; get a new symbol. 114 | c.x++ 115 | return c.get_vlc_symbol(state, bits) 116 | } 117 | } 118 | 119 | // Simple sign extension. 120 | func sign_extend(n int32, bits uint) int32 { 121 | if bits == 8 { 122 | ret := int8(n) 123 | return int32(ret) 124 | } else { 125 | ret := n 126 | ret <<= 32 - bits 127 | ret >>= 32 - bits 128 | return ret 129 | } 130 | } 131 | 132 | // Gets the next Golomb-Rice coded symbol. 133 | // 134 | // See: 3.8.2.3. Scalar Mode 135 | func (c *Coder) get_vlc_symbol(state *State, bits uint) int32 { 136 | i := state.count 137 | k := uint32(0) 138 | 139 | for i < state.error_sum { 140 | k++ 141 | i += i 142 | } 143 | 144 | v := c.get_sr_golomb(k, bits) 145 | 146 | if 2*state.drift < -state.count { 147 | v = -1 - v 148 | } 149 | 150 | ret := sign_extend(v+state.bias, bits) 151 | 152 | state.error_sum += abs32(v) 153 | state.drift += v 154 | 155 | if state.count == 128 { 156 | state.count >>= 1 157 | state.drift >>= 1 158 | state.error_sum >>= 1 159 | } 160 | state.count++ 161 | if state.drift <= -state.count { 162 | state.bias = max32(state.bias-1, -128) 163 | state.drift = max32(state.drift+state.count, -state.count+1) 164 | } else if state.drift > 0 { 165 | state.bias = min32(state.bias+1, 127) 166 | state.drift = min32(state.drift-state.count, 0) 167 | } 168 | 169 | return ret 170 | } 171 | 172 | // Gets the next signed Golomb-Rice code 173 | // 174 | // See: 3.8.2.1. Signed Golomb Rice Codes 175 | func (c *Coder) get_sr_golomb(k uint32, bits uint) int32 { 176 | v := c.get_ur_golomb(k, bits) 177 | if v&1 == 1 { 178 | return -(v >> 1) - 1 179 | } else { 180 | return v >> 1 181 | } 182 | } 183 | 184 | // Gets the next unsigned Golomb-Rice code 185 | // 186 | // See: 3.8.2.1. Signed Golomb Rice Codes 187 | func (c *Coder) get_ur_golomb(k uint32, bits uint) int32 { 188 | for prefix := 0; prefix < 12; prefix++ { 189 | if c.r.u(1) == 1 { 190 | return int32(c.r.u(k)) + int32((prefix << k)) 191 | } 192 | } 193 | return int32(c.r.u(uint32(bits))) + 11 194 | } 195 | -------------------------------------------------------------------------------- /ffv1/record.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/dwbuiten/go-ffv1/ffv1/rangecoder" 7 | ) 8 | 9 | type configRecord struct { 10 | version uint8 11 | micro_version uint8 12 | coder_type uint8 13 | state_transition_delta [256]int16 14 | colorspace_type uint8 15 | bits_per_raw_sample uint8 16 | chroma_planes bool 17 | log2_h_chroma_subsample uint8 18 | log2_v_chroma_subsample uint8 19 | extra_plane bool 20 | num_h_slices_minus1 uint8 21 | num_v_slices_minus1 uint8 22 | quant_table_set_count uint8 23 | context_count [maxQuantTables]int32 24 | quant_tables [maxQuantTables][maxContextInputs][256]int16 25 | states_coded bool 26 | initial_state_delta [][][]int16 27 | ec uint8 28 | intra uint8 29 | } 30 | 31 | // Parses the configuration record from the codec private data. 32 | // 33 | // See: * 4.1. Parameters 34 | // * 4.2. Configuration Record 35 | func parseConfigRecord(buf []byte, record *configRecord) error { 36 | // Before we do anything, CRC check. 37 | // 38 | // See: 4.2.2. configuration_record_crc_parity 39 | if crc32MPEG2(buf) != 0 { 40 | return fmt.Errorf("failed CRC check for configuration record") 41 | } 42 | c := rangecoder.NewCoder(buf) 43 | 44 | // 4. Bitstream 45 | state := make([]uint8, contextSize) 46 | for i := 0; i < contextSize; i++ { 47 | state[i] = 128 48 | } 49 | 50 | // 4.1.1. version 51 | record.version = uint8(c.UR(state)) 52 | if record.version != 3 { 53 | return fmt.Errorf("only FFV1 version 3 is supported") 54 | } 55 | 56 | // 4.1.2. micro_version 57 | record.micro_version = uint8(c.UR(state)) 58 | if record.micro_version < 1 { 59 | return fmt.Errorf("only FFV1 micro version >1 supported") 60 | } 61 | 62 | // 4.1.3. coder_type 63 | record.coder_type = uint8(c.UR(state)) 64 | if record.coder_type > 2 { 65 | return fmt.Errorf("invalid coder_type: %d", record.coder_type) 66 | } 67 | 68 | // 4.1.4. state_transition_delta 69 | if record.coder_type > 1 { 70 | for i := 1; i < 256; i++ { 71 | record.state_transition_delta[i] = int16(c.SR(state)) 72 | } 73 | } 74 | 75 | // 4.1.5. colorspace_type 76 | record.colorspace_type = uint8(c.UR(state)) 77 | if record.colorspace_type > 1 { 78 | return fmt.Errorf("invalid colorspace_type: %d", record.colorspace_type) 79 | } 80 | 81 | // 4.1.7. bits_per_raw_sample 82 | record.bits_per_raw_sample = uint8(c.UR(state)) 83 | if record.bits_per_raw_sample == 0 { 84 | record.bits_per_raw_sample = 8 85 | } 86 | if record.coder_type == 0 && record.bits_per_raw_sample != 8 { 87 | return fmt.Errorf("golomb-rice mode cannot have >8bit per sample") 88 | } 89 | 90 | // 4.1.6. chroma_planes 91 | record.chroma_planes = c.BR(state) 92 | if record.colorspace_type == 1 && !record.chroma_planes { 93 | return fmt.Errorf("RGB must contain chroma planes") 94 | } 95 | 96 | // 4.1.8. log2_h_chroma_subsample 97 | record.log2_h_chroma_subsample = uint8(c.UR(state)) 98 | if record.colorspace_type == 1 && record.log2_h_chroma_subsample != 0 { 99 | return fmt.Errorf("RGB cannot be subsampled") 100 | } 101 | 102 | // 4.1.9. log2_v_chroma_subsample 103 | record.log2_v_chroma_subsample = uint8(c.UR(state)) 104 | if record.colorspace_type == 1 && record.log2_v_chroma_subsample != 0 { 105 | return fmt.Errorf("RGB cannot be subsampled") 106 | } 107 | 108 | // 4.1.10. extra_plane 109 | record.extra_plane = c.BR(state) 110 | // 4.1.11. num_h_slices 111 | record.num_h_slices_minus1 = uint8(c.UR(state)) 112 | // 4.1.12. num_v_slices 113 | record.num_v_slices_minus1 = uint8(c.UR(state)) 114 | 115 | // 4.1.13. quant_table_set_count 116 | record.quant_table_set_count = uint8(c.UR(state)) 117 | if record.quant_table_set_count == 0 { 118 | return fmt.Errorf("quant_table_set_count may not be zero") 119 | } else if record.quant_table_set_count > maxQuantTables { 120 | return fmt.Errorf("too many quant tables: %d > %d", record.quant_table_set_count, maxQuantTables) 121 | } 122 | 123 | for i := 0; i < int(record.quant_table_set_count); i++ { 124 | // 4.9. Quantization Table Set 125 | scale := 1 126 | for j := 0; j < maxContextInputs; j++ { 127 | // Each table has its own state table. 128 | quant_state := make([]byte, contextSize) 129 | for qs := 0; qs < contextSize; qs++ { 130 | quant_state[qs] = 128 131 | } 132 | v := 0 133 | for k := 0; k < 128; { 134 | len_minus1 := c.UR(quant_state) 135 | for a := 0; a < int(len_minus1+1); a++ { 136 | record.quant_tables[i][j][k] = int16(scale * v) 137 | k++ 138 | } 139 | v++ 140 | } 141 | for k := 1; k < 128; k++ { 142 | record.quant_tables[i][j][256-k] = -record.quant_tables[i][j][k] 143 | } 144 | record.quant_tables[i][j][128] = -record.quant_tables[i][j][127] 145 | scale *= 2*v - 1 146 | } 147 | record.context_count[i] = int32((scale + 1) / 2) 148 | } 149 | 150 | // Why on earth did they choose to do a variable length buffer in the 151 | // *middle and start* of a 3D array? 152 | record.initial_state_delta = make([][][]int16, int(record.quant_table_set_count)) 153 | for i := 0; i < int(record.quant_table_set_count); i++ { 154 | record.initial_state_delta[i] = make([][]int16, int(record.context_count[i])) 155 | for j := 0; j < int(record.context_count[i]); j++ { 156 | record.initial_state_delta[i][j] = make([]int16, contextSize) 157 | } 158 | states_coded := c.BR(state) 159 | if states_coded { 160 | for j := 0; j < int(record.context_count[i]); j++ { 161 | for k := 0; k < contextSize; k++ { 162 | record.initial_state_delta[i][j][k] = int16(c.SR(state)) 163 | } 164 | } 165 | } 166 | } 167 | 168 | // 4.1.16. ec 169 | record.ec = uint8(c.UR(state)) 170 | // 4.1.17. intra 171 | record.intra = uint8(c.UR(state)) 172 | 173 | return nil 174 | } 175 | 176 | // Initializes initial state for the range coder. 177 | // 178 | // See: 4.1.15. initial_state_delta 179 | func (d *Decoder) initializeStates() { 180 | for i := 1; i < 256; i++ { 181 | d.state_transition[i] = uint8(int16(rangecoder.DefaultStateTransition[i]) + d.record.state_transition_delta[i]) 182 | } 183 | 184 | d.initial_states = make([][][]uint8, len(d.record.initial_state_delta)) 185 | for i := 0; i < len(d.record.initial_state_delta); i++ { 186 | d.initial_states[i] = make([][]uint8, len(d.record.initial_state_delta[i])) 187 | for j := 0; j < len(d.record.initial_state_delta[i]); j++ { 188 | d.initial_states[i][j] = make([]uint8, len(d.record.initial_state_delta[i][j])) 189 | for k := 0; k < len(d.record.initial_state_delta[i][j]); k++ { 190 | pred := int16(128) 191 | if j != 0 { 192 | pred = int16(d.initial_states[i][j-1][k]) 193 | } 194 | d.initial_states[i][j][k] = uint8((pred + d.record.initial_state_delta[i][j][k]) & 255) 195 | } 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /ffv1/api.go: -------------------------------------------------------------------------------- 1 | // Package ffv1 implements an FFV1 Version 3 decoder based off of 2 | // draft-ietf-cellar-ffv1. 3 | package ffv1 4 | 5 | import ( 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | // Decoder is a FFV1 decoder instance. 11 | type Decoder struct { 12 | width uint32 13 | height uint32 14 | record configRecord 15 | state_transition [256]uint8 16 | initial_states [][][]uint8 17 | current_frame internalFrame 18 | } 19 | 20 | // Frame contains a decoded FFV1 frame and relevant 21 | // data about the frame. 22 | // 23 | // If BitDepth is 8, image data is in Buf. If it is anything else, 24 | // image data is in Buf16. 25 | // 26 | // Image data consists of up to four contiguous planes, as follows: 27 | // - If ColorSpace is YCbCr: 28 | // - Plane 0 is Luma (always present) 29 | // - If HasChroma is true, the next two planes are Cr and Cr, subsampled by 30 | // ChromaSubsampleV and ChromaSubsampleH. 31 | // - If HasAlpha is true, the next plane is alpha. 32 | // - If ColorSpace is RGB: 33 | // - Plane 0 is Green 34 | // - Plane 1 is Blue 35 | // - Plane 2 is Red 36 | // - If HasAlpha is true, plane 4 is alpha. 37 | type Frame struct { 38 | // Image data. Valid only when BitDepth is 8. 39 | Buf [][]byte 40 | // Image data. Valid only when BitDepth is greater than 8. 41 | Buf16 [][]uint16 42 | // Unexported 32-bit scratch buffer for 16-bit JPEG2000-RCT RGB 43 | buf32 [][]uint32 44 | // Width of the frame, in pixels. 45 | Width uint32 46 | // Height of the frame, in pixels. 47 | Height uint32 48 | // BitDepth of the frame (8-16). 49 | BitDepth uint8 50 | // ColorSpace of the frame. See the ColorSpace constants. 51 | ColorSpace int 52 | // Whether or not chroma planes are present. 53 | HasChroma bool 54 | // Whether or not an alpha plane is present. 55 | HasAlpha bool 56 | // The log2 vertical chroma subampling value. 57 | ChromaSubsampleV uint8 58 | // The log2 horizontal chroma subsampling value. 59 | ChromaSubsampleH uint8 60 | } 61 | 62 | // NewDecoder creates a new FFV1 decoder instance. 63 | // 64 | // 'record' is the codec private data provided by the container. For 65 | // Matroska, this is what is in CodecPrivate (adjusted for e.g. VFW 66 | // data that may be before it). For ISOBMFF, this is the 'glbl' box. 67 | // 68 | // 'width' and 'height' are the frame width and height provided by 69 | // the container. 70 | func NewDecoder(record []byte, width uint32, height uint32) (*Decoder, error) { 71 | ret := new(Decoder) 72 | 73 | if width == 0 || height == 0 { 74 | return nil, fmt.Errorf("invalid dimensions: %dx%d", width, height) 75 | } 76 | 77 | if len(record) == 0 { 78 | return nil, fmt.Errorf("invalid record with length zero") 79 | } 80 | 81 | ret.width = width 82 | ret.height = height 83 | 84 | err := parseConfigRecord(record, &ret.record) 85 | if err != nil { 86 | return nil, fmt.Errorf("invalid v3 configuration record: %s", err.Error()) 87 | } 88 | 89 | ret.initializeStates() 90 | 91 | return ret, nil 92 | } 93 | 94 | // DecodeFrame takes a packet and decodes it to a ffv1.Frame. 95 | // 96 | // Slice threading is used by default, with one goroutine per 97 | // slice. 98 | func (d *Decoder) DecodeFrame(frame []byte) (*Frame, error) { 99 | 100 | // Allocate and fill frame info 101 | ret := new(Frame) 102 | ret.Width = d.width 103 | ret.Height = d.height 104 | ret.BitDepth = d.record.bits_per_raw_sample 105 | ret.ColorSpace = int(d.record.colorspace_type) 106 | ret.HasChroma = d.record.chroma_planes 107 | ret.HasAlpha = d.record.extra_plane 108 | if ret.HasChroma { 109 | ret.ChromaSubsampleV = d.record.log2_v_chroma_subsample 110 | ret.ChromaSubsampleH = d.record.log2_h_chroma_subsample 111 | } 112 | 113 | numPlanes := 1 114 | if d.record.chroma_planes { 115 | numPlanes += 2 116 | } 117 | if d.record.extra_plane { 118 | numPlanes++ 119 | } 120 | 121 | // Hideous and temporary. 122 | if d.record.bits_per_raw_sample == 8 { 123 | ret.Buf = make([][]byte, numPlanes) 124 | ret.Buf[0] = make([]byte, int(d.width*d.height)) 125 | if d.record.chroma_planes { 126 | chromaWidth := d.width >> d.record.log2_h_chroma_subsample 127 | chromaHeight := d.height >> d.record.log2_v_chroma_subsample 128 | ret.Buf[1] = make([]byte, int(chromaWidth*chromaHeight)) 129 | ret.Buf[2] = make([]byte, int(chromaWidth*chromaHeight)) 130 | } 131 | if d.record.extra_plane { 132 | ret.Buf[3] = make([]byte, int(d.width*d.height)) 133 | } 134 | } 135 | 136 | // We allocate *both* if it's 8bit RGB since I'm a terrible person and 137 | // I wanted to use it as a scratch space, since JPEG2000-RCT is very 138 | // annoyingly coded as n+1 bits, and I wanted the implementation 139 | // to be straightforward... RIP. 140 | if d.record.bits_per_raw_sample > 8 || d.record.colorspace_type == 1 { 141 | ret.Buf16 = make([][]uint16, numPlanes) 142 | ret.Buf16[0] = make([]uint16, int(d.width*d.height)) 143 | if d.record.chroma_planes { 144 | chromaWidth := d.width >> d.record.log2_h_chroma_subsample 145 | chromaHeight := d.height >> d.record.log2_v_chroma_subsample 146 | ret.Buf16[1] = make([]uint16, int(chromaWidth*chromaHeight)) 147 | ret.Buf16[2] = make([]uint16, int(chromaWidth*chromaHeight)) 148 | } 149 | if d.record.extra_plane { 150 | ret.Buf16[3] = make([]uint16, int(d.width*d.height)) 151 | } 152 | } 153 | 154 | // For 16-bit RGB we need a 32-bit scratch space beause we need to predict 155 | // based on 17-bit values in the JPEG2000-RCT space, so just allocate a 156 | // whole frame, because I am lazy. Is it slow? Yes. 157 | if d.record.bits_per_raw_sample == 16 && d.record.colorspace_type == 1 { 158 | ret.buf32 = make([][]uint32, numPlanes) 159 | ret.buf32[0] = make([]uint32, int(d.width*d.height)) 160 | ret.buf32[1] = make([]uint32, int(d.width*d.height)) 161 | ret.buf32[2] = make([]uint32, int(d.width*d.height)) 162 | if d.record.extra_plane { 163 | ret.buf32[3] = make([]uint32, int(d.width*d.height)) 164 | } 165 | } 166 | 167 | // We parse the frame's keyframe info outside the slice decoding 168 | // loop so we know ahead of time if each slice has to refresh its 169 | // states or not. This allows easy slice threading. 170 | d.current_frame.keyframe = isKeyframe(frame) 171 | 172 | // We parse all the footers ahead of time too, for the same reason. 173 | // It allows us to know all the slice positions and sizes. 174 | // 175 | // See: 9.1.1. Multi-threading Support and Independence of Slices 176 | err := d.parseFooters(frame, &d.current_frame) 177 | if err != nil { 178 | return nil, fmt.Errorf("invalid frame footer: %s", err.Error()) 179 | } 180 | 181 | // Slice threading lazymode 182 | errs := make([]error, len(d.current_frame.slices)) 183 | wg := new(sync.WaitGroup) 184 | for i := 0; i < len(d.current_frame.slices); i++ { 185 | wg.Add(1) 186 | go func(wg *sync.WaitGroup, errs []error, n int) { 187 | errs[n] = d.decodeSlice(frame, &d.current_frame, n, ret) 188 | wg.Done() 189 | }(wg, errs, i) 190 | } 191 | wg.Wait() 192 | for i, err := range errs { 193 | if err != nil { 194 | return nil, fmt.Errorf("slice %d failed: %s", i, err.Error()) 195 | } 196 | } 197 | 198 | // Delete the scratch buffer, if needed, as per above. 199 | if d.record.bits_per_raw_sample == 8 && d.record.colorspace_type == 1 { 200 | ret.Buf16 = nil 201 | } 202 | 203 | // We'll never need this again. 204 | ret.buf32 = nil 205 | 206 | return ret, nil 207 | } 208 | -------------------------------------------------------------------------------- /ffv1/slice.go: -------------------------------------------------------------------------------- 1 | package ffv1 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "github.com/dwbuiten/go-ffv1/ffv1/golomb" 8 | "github.com/dwbuiten/go-ffv1/ffv1/rangecoder" 9 | ) 10 | 11 | type internalFrame struct { 12 | keyframe bool 13 | slice_info []sliceInfo 14 | slices []slice 15 | } 16 | 17 | type sliceInfo struct { 18 | pos int 19 | size uint32 20 | error_status uint8 21 | } 22 | 23 | type slice struct { 24 | header sliceHeader 25 | start_x uint32 26 | start_y uint32 27 | width uint32 28 | height uint32 29 | state [][][]uint8 30 | golomb_state [][]golomb.State 31 | } 32 | 33 | type sliceHeader struct { 34 | slice_width_minus1 uint32 35 | slice_height_minus1 uint32 36 | slice_x uint32 37 | slice_y uint32 38 | quant_table_set_index []uint8 39 | picture_structure uint8 40 | sar_num uint32 41 | sar_den uint32 42 | } 43 | 44 | // Counts the number of slices in a frame, as described in 45 | // 9.1.1. Multi-threading Support and Independence of Slices. 46 | // 47 | // See: 4.8. Slice Footer 48 | func countSlices(buf []byte, header *internalFrame, ec bool) error { 49 | footerSize := 3 50 | if ec { 51 | footerSize += 5 52 | } 53 | 54 | // Go over the packet from the end to start, reading the footer, 55 | // so we can derive the slice positions within the packet, and 56 | // allow multithreading. 57 | endPos := len(buf) 58 | header.slice_info = nil 59 | for endPos > 0 { 60 | var info sliceInfo 61 | 62 | // 4.8.1. slice_size 63 | size := uint32(buf[endPos-footerSize]) << 16 64 | size |= uint32(buf[endPos-footerSize+1]) << 8 65 | size |= uint32(buf[endPos-footerSize+2]) 66 | info.size = size 67 | 68 | // 4.8.2. error_status 69 | info.error_status = uint8(buf[endPos-footerSize+3]) 70 | 71 | info.pos = endPos - int(size) - footerSize 72 | header.slice_info = append([]sliceInfo{info}, header.slice_info...) //prepend 73 | endPos = info.pos 74 | } 75 | 76 | if endPos < 0 { 77 | return fmt.Errorf("invalid slice footer") 78 | } 79 | 80 | return nil 81 | } 82 | 83 | // Parses all footers in a frame and allocates any necessary slice structures. 84 | // 85 | // See: * 9.1.1. Multi-threading Support and Independence of Slices 86 | // * 3.8.1.3. Initial Values for the Context Model 87 | // * 3.8.2.4. Initial Values for the VLC context state 88 | func (d *Decoder) parseFooters(buf []byte, header *internalFrame) error { 89 | err := countSlices(buf, header, d.record.ec != 0) 90 | if err != nil { 91 | return fmt.Errorf("couldn't count slices: %s", err.Error()) 92 | } 93 | 94 | slices := make([]slice, len(header.slice_info)) 95 | if !header.keyframe { 96 | if len(slices) != len(header.slices) { 97 | return fmt.Errorf("inter frames must have the same number of slices as the preceding intra frame") 98 | } 99 | for i := 0; i < len(slices); i++ { 100 | slices[i].state = header.slices[i].state 101 | } 102 | if d.record.coder_type == 0 { 103 | for i := 0; i < len(slices); i++ { 104 | slices[i].golomb_state = header.slices[i].golomb_state 105 | } 106 | } 107 | } 108 | header.slices = slices 109 | 110 | return nil 111 | } 112 | 113 | // Parses a slice's header. 114 | // 115 | // See: 4.5. Slice Header 116 | func (d *Decoder) parseSliceHeader(c *rangecoder.Coder, s *slice) { 117 | // 4. Bitstream 118 | slice_state := make([]uint8, contextSize) 119 | for i := 0; i < contextSize; i++ { 120 | slice_state[i] = 128 121 | } 122 | 123 | // 4.5.1. slice_x 124 | s.header.slice_x = c.UR(slice_state) 125 | // 4.5.2. slice_y 126 | s.header.slice_y = c.UR(slice_state) 127 | // 4.5.3 slice_width 128 | s.header.slice_width_minus1 = c.UR(slice_state) 129 | // 4.5.4 slice_height 130 | s.header.slice_height_minus1 = c.UR(slice_state) 131 | 132 | // 4.5.5. quant_table_set_index_count 133 | quant_table_set_index_count := 1 134 | if d.record.chroma_planes { 135 | quant_table_set_index_count++ 136 | } 137 | if d.record.extra_plane { 138 | quant_table_set_index_count++ 139 | } 140 | 141 | // 4.5.6. quant_table_set_index 142 | s.header.quant_table_set_index = make([]uint8, quant_table_set_index_count) 143 | for i := 0; i < quant_table_set_index_count; i++ { 144 | s.header.quant_table_set_index[i] = uint8(c.UR(slice_state)) 145 | } 146 | 147 | // 4.5.7. picture_structure 148 | s.header.picture_structure = uint8(c.UR(slice_state)) 149 | 150 | // It's really weird for slices within the same frame to code 151 | // their own SAR values... 152 | // 153 | // See: * 4.5.8. sar_num 154 | // * 4.5.9. sar_den 155 | s.header.sar_num = c.UR(slice_state) 156 | s.header.sar_den = c.UR(slice_state) 157 | 158 | // Calculate bounaries for easy use elsewhere 159 | // 160 | // See: * 4.6.3. slice_pixel_height 161 | // * 4.6.4. slice_pixel_y 162 | // * 4.7.2. slice_pixel_width 163 | // * 4.7.3. slice_pixel_x 164 | s.start_x = s.header.slice_x * d.width / (uint32(d.record.num_h_slices_minus1) + 1) 165 | s.start_y = s.header.slice_y * d.height / (uint32(d.record.num_v_slices_minus1) + 1) 166 | s.width = ((s.header.slice_x + s.header.slice_width_minus1 + 1) * d.width / (uint32(d.record.num_h_slices_minus1) + 1)) - s.start_x 167 | s.height = ((s.header.slice_y + s.header.slice_height_minus1 + 1) * d.height / (uint32(d.record.num_v_slices_minus1) + 1)) - s.start_y 168 | } 169 | 170 | // Line decoding. 171 | // 172 | // So, so many arguments. I would have just inlined this whole thing 173 | // but it needs to be separate because of RGB mode where every line 174 | // is done in its entirety instead of per plane. 175 | // 176 | // Many could be refactored into being in the context, but I haven't 177 | // got to it yet, so instead, I shall repent once for each function 178 | // argument, twice daily. 179 | // 180 | // See: 4.7. Line 181 | func (d *Decoder) decodeLine(c *rangecoder.Coder, gc *golomb.Coder, s *slice, frame *Frame, w int, h int, stride int, offset int, y int, p int, qt int) { 182 | // Runs are horizontal and thus cannot run more than a line. 183 | // 184 | // See: 3.8.2.2.1. Run Length Coding 185 | if gc != nil { 186 | gc.NewLine() 187 | } 188 | 189 | // 4.7.4. sample_difference 190 | for x := 0; x < w; x++ { 191 | var sign bool 192 | 193 | var buf []byte 194 | var buf16 []uint16 195 | var buf32 []uint32 196 | if d.record.bits_per_raw_sample == 8 && d.record.colorspace_type != 1 { 197 | buf = frame.Buf[p][offset:] 198 | } else if d.record.bits_per_raw_sample == 16 && d.record.colorspace_type == 1 { 199 | buf32 = frame.buf32[p][offset:] 200 | } else { 201 | buf16 = frame.Buf16[p][offset:] 202 | } 203 | 204 | // 3.8. Coding of the Sample Difference 205 | shift := d.record.bits_per_raw_sample 206 | if d.record.colorspace_type == 1 { 207 | shift = d.record.bits_per_raw_sample + 1 208 | } 209 | 210 | // Derive neighbours 211 | // 212 | // See pred.go for details. 213 | var T, L, t, l, tr, tl int 214 | if d.record.bits_per_raw_sample == 8 && d.record.colorspace_type != 1 { 215 | T, L, t, l, tr, tl = deriveBorders(buf, x, y, w, h, stride) 216 | } else if d.record.bits_per_raw_sample == 16 && d.record.colorspace_type == 1 { 217 | T, L, t, l, tr, tl = deriveBorders32(buf32, x, y, w, h, stride) 218 | } else { 219 | T, L, t, l, tr, tl = deriveBorders16(buf16, x, y, w, h, stride) 220 | } 221 | 222 | // See pred.go for details. 223 | // 224 | // See also: * 3.4. Context 225 | // * 3.6. Quantization Table Set Indexes 226 | context := getContext(d.record.quant_tables[s.header.quant_table_set_index[qt]], T, L, t, l, tr, tl) 227 | if context < 0 { 228 | context = -context 229 | sign = true 230 | } else { 231 | sign = false 232 | } 233 | 234 | var diff int32 235 | if gc != nil { 236 | diff = gc.SG(context, &s.golomb_state[qt][context], uint(shift)) 237 | } else { 238 | diff = c.SR(s.state[qt][context]) 239 | } 240 | 241 | // 3.4. Context 242 | if sign { 243 | diff = -diff 244 | } 245 | 246 | // 3.8. Coding of the Sample Difference 247 | val := diff 248 | if d.record.colorspace_type == 0 && d.record.bits_per_raw_sample == 16 && gc == nil { 249 | // 3.3. Median Predictor 250 | var left16s int 251 | var top16s int 252 | var diag16s int 253 | 254 | if l >= 32768 { 255 | left16s = l - 65536 256 | } else { 257 | left16s = l 258 | } 259 | if t >= 32768 { 260 | top16s = t - 65536 261 | } else { 262 | top16s = t 263 | } 264 | if tl >= 32768 { 265 | diag16s = tl - 65536 266 | } else { 267 | diag16s = tl 268 | } 269 | 270 | val += int32(getMedian(left16s, top16s, left16s+top16s-diag16s)) 271 | } else { 272 | val += int32(getMedian(l, t, l+t-tl)) 273 | } 274 | 275 | val = val & ((1 << shift) - 1) 276 | 277 | if d.record.bits_per_raw_sample == 8 && d.record.colorspace_type != 1 { 278 | buf[(y*stride)+x] = byte(val) 279 | } else if d.record.bits_per_raw_sample == 16 && d.record.colorspace_type == 1 { 280 | buf32[(y*stride)+x] = uint32(val) 281 | } else { 282 | buf16[(y*stride)+x] = uint16(val) 283 | } 284 | } 285 | } 286 | 287 | // Decoding happens here. 288 | // 289 | // See: * 4.6. Slice Content 290 | func (d *Decoder) decodeSliceContent(c *rangecoder.Coder, gc *golomb.Coder, si *sliceInfo, s *slice, frame *Frame) { 291 | // 4.6.1. primary_color_count 292 | primary_color_count := 1 293 | chroma_planes := 0 294 | if d.record.chroma_planes { 295 | chroma_planes = 2 296 | primary_color_count += 2 297 | } 298 | if d.record.extra_plane { 299 | primary_color_count++ 300 | } 301 | 302 | if d.record.colorspace_type != 1 { 303 | // YCbCr Mode 304 | // 305 | // Planes are independent. 306 | // 307 | // See: 3.7.1. YCbCr 308 | for p := 0; p < primary_color_count; p++ { 309 | var plane_pixel_height int 310 | var plane_pixel_width int 311 | var plane_pixel_stride int 312 | var start_x int 313 | var start_y int 314 | var quant_table int 315 | 316 | // See: * 4.6.2. plane_pixel_height 317 | // * 4.7.1. plane_pixel_width 318 | if p == 0 || p == 1+chroma_planes { 319 | plane_pixel_height = int(s.height) 320 | plane_pixel_width = int(s.width) 321 | plane_pixel_stride = int(d.width) 322 | start_x = int(s.start_x) 323 | start_y = int(s.start_y) 324 | if p == 0 { 325 | quant_table = 0 326 | } else { 327 | quant_table = chroma_planes 328 | } 329 | } else { 330 | // This is, of course, silly, but I want to do it "by the spec". 331 | plane_pixel_height = int(math.Ceil(float64(s.height) / float64(uint32(1)<= 9 && d.record.bits_per_raw_sample <= 15 && !d.record.extra_plane { 373 | // See: 3.7.2. RGB 374 | rctMid(frame.Buf16, int(s.width), int(s.height), int(d.width), offset, uint(d.record.bits_per_raw_sample)) 375 | } else { 376 | rct16(frame.Buf16, frame.buf32, int(s.width), int(s.height), int(d.width), offset) 377 | } 378 | } 379 | } 380 | 381 | // Determines whether a given frame is a keyframe. 382 | // 383 | // See: 4.3. Frame 384 | func isKeyframe(buf []byte) bool { 385 | // 4. Bitstream 386 | state := make([]uint8, contextSize) 387 | for i := 0; i < contextSize; i++ { 388 | state[i] = 128 389 | } 390 | 391 | c := rangecoder.NewCoder(buf) 392 | 393 | return c.BR(state) 394 | } 395 | 396 | // Resets the range coder and Golomb-Rice coder states. 397 | func (d *Decoder) resetSliceStates(s *slice) { 398 | // Range coder states 399 | s.state = make([][][]uint8, len(d.initial_states)) 400 | for i := 0; i < len(d.initial_states); i++ { 401 | s.state[i] = make([][]uint8, len(d.initial_states[i])) 402 | for j := 0; j < len(d.initial_states[i]); j++ { 403 | s.state[i][j] = make([]uint8, len(d.initial_states[i][j])) 404 | copy(s.state[i][j], d.initial_states[i][j]) 405 | } 406 | } 407 | 408 | // Golomb-Rice Code states 409 | if d.record.coder_type == 0 { 410 | s.golomb_state = make([][]golomb.State, d.record.quant_table_set_count) 411 | for i := 0; i < len(s.golomb_state); i++ { 412 | s.golomb_state[i] = make([]golomb.State, d.record.context_count[i]) 413 | for j := 0; j < len(s.golomb_state[i]); j++ { 414 | s.golomb_state[i][j] = golomb.NewState() 415 | } 416 | } 417 | } 418 | } 419 | 420 | func (d *Decoder) decodeSlice(buf []byte, header *internalFrame, slicenum int, frame *Frame) error { 421 | // Before we do anything, let's try and check the integrity 422 | // 423 | // See: * 4.8.2. error_status 424 | // * 4.8.3. slice_crc_parity 425 | if d.record.ec == 1 { 426 | if header.slice_info[slicenum].error_status != 0 { 427 | return fmt.Errorf("error_status is non-zero: %d", header.slice_info[slicenum].error_status) 428 | } 429 | 430 | sliceBuf := buf[header.slice_info[slicenum].pos:] 431 | sliceBuf = sliceBuf[:header.slice_info[slicenum].size+8] // 8 bytes for footer size 432 | if crc32MPEG2(sliceBuf) != 0 { 433 | return fmt.Errorf("CRC mismatch") 434 | } 435 | } 436 | 437 | // If this is a keyframe, refresh states. 438 | // 439 | // See: * 3.8.1.3. Initial Values for the Context Model 440 | // * 3.8.2.4. Initial Values for the VLC context state 441 | if header.keyframe { 442 | d.resetSliceStates(&header.slices[slicenum]) 443 | } 444 | 445 | c := rangecoder.NewCoder(buf[header.slice_info[slicenum].pos:]) 446 | 447 | // 4. Bitstream 448 | state := make([]uint8, contextSize) 449 | for i := 0; i < contextSize; i++ { 450 | state[i] = 128 451 | } 452 | 453 | // Skip keyframe bit on slice 0 454 | if slicenum == 0 { 455 | c.BR(state) 456 | } 457 | 458 | if d.record.coder_type == 2 { // Custom state transition table 459 | c.SetTable(d.state_transition) 460 | } 461 | 462 | d.parseSliceHeader(c, &header.slices[slicenum]) 463 | 464 | var gc *golomb.Coder 465 | if d.record.coder_type == 0 { 466 | // We're switching to Golomb-Rice mode now so we need the bitstream 467 | // position. 468 | // 469 | // See: 3.8.1.1.1. Termination 470 | c.SentinalEnd() 471 | offset := c.GetPos() - 1 472 | gc = golomb.NewCoder(buf[header.slice_info[slicenum].pos+offset:]) 473 | } 474 | 475 | // Don't worry, I fully understand how non-idiomatic and 476 | // ugly passing both c and gc is. 477 | d.decodeSliceContent(c, gc, &header.slice_info[slicenum], &header.slices[slicenum], frame) 478 | 479 | return nil 480 | } 481 | --------------------------------------------------------------------------------