-
Notifications
You must be signed in to change notification settings - Fork 224
/
vp9_frame.go
142 lines (123 loc) · 3.47 KB
/
vp9_frame.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package vpx
// https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
import (
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)
// TODO: vpx frame?
const (
vp9FeatureProfile = 1
vp9FeatureLevel = 2
vp9FeatureBitDepth = 3
vp9FeatureChromaSubsampling = 4
)
var vp9FeatureIDNames = scalar.UintMapSymStr{
vp9FeatureProfile: "Profile",
vp9FeatureLevel: "Level",
vp9FeatureBitDepth: "Bit Depth",
vp9FeatureChromaSubsampling: "Chroma Subsampling",
}
const (
CS_UNKNOWN = 0
CS_BT_601 = 1
CS_BT_709 = 2
CS_SMPTE_170 = 3
CS_SMPTE_240 = 4
CS_BT_2020 = 5
CS_RESERVED = 6
CS_RGB = 7
)
var vp9ColorSpaceNames = scalar.UintMapSymStr{
CS_UNKNOWN: "unknown",
CS_BT_601: "bt_601",
CS_BT_709: "bt_709",
CS_SMPTE_170: "smpte_170",
CS_SMPTE_240: "smpte_240",
CS_BT_2020: "bt_2020",
CS_RESERVED: "reserved",
CS_RGB: "rgb",
}
var vp9ProfilesMap = scalar.UintMapDescription{
0: "8 bit/sample, chroma subsampling: 4:2:0",
1: "8 bit, chroma subsampling: 4:2:2, 4:4:0, 4:4:4",
2: "10–12 bit, chroma subsampling: 4:2:0",
3: "10–12 bit, chroma subsampling: 4:2:2, 4:4:0, 4:4:4",
}
func init() {
interp.RegisterFormat(
format.VP9_Frame,
&decode.Format{
Description: "VP9 frame",
DecodeFn: vp9Decode,
})
}
func vp9DecodeFrameSyncCode(d *decode.D) {
d.FieldU8("frame_sync_byte_0")
d.FieldU8("frame_sync_byte_1")
d.FieldU8("frame_sync_byte_2")
}
func vp9DecodeColorConfig(d *decode.D, profile int) {
bitDepth := 8
if profile >= 2 {
tenOrTwelveBit := d.FieldBool("ten_or_twelve_bit")
if tenOrTwelveBit {
bitDepth = 12
} else {
bitDepth = 10
}
}
d.FieldValueUint("bit_depth", uint64(bitDepth))
colorSpace := d.FieldU3("color_space", vp9ColorSpaceNames)
_, colorSpaceOk := vp9ColorSpaceNames[colorSpace]
if !colorSpaceOk || colorSpace != CS_RGB {
d.FieldU1("color_range")
if profile == 1 || profile == 3 {
d.FieldU1("subsampling_x")
d.FieldU1("subsampling_y")
d.FieldU1("reserved_zero1")
} else {
d.FieldValueUint("subsampling_x", 1)
d.FieldValueUint("subsampling_y", 1)
}
} else {
d.FieldValueUint("color_range", 1)
if profile == 1 || profile == 3 {
d.FieldValueUint("subsampling_x", 0)
d.FieldValueUint("subsampling_y", 0)
d.FieldU1("reserved_zero2")
}
}
}
func vp9DecodeFrameSize(d *decode.D) {
d.FieldUintFn("frame_width", func(d *decode.D) uint64 { return d.U16() + 1 })
d.FieldUintFn("frame_height", func(d *decode.D) uint64 { return d.U16() + 1 })
}
func vp9Decode(d *decode.D) any {
// TODO: header_size at end? even for show_existing_frame?
d.FieldU2("frame_marker")
profileLowBit := d.FieldU1("profile_low_bit")
profileHighBit := d.FieldU1("profile_high_bit")
profile := int(profileHighBit<<1 + profileLowBit)
d.FieldValueUint("profile", uint64(profile), vp9ProfilesMap)
if profile == 3 {
d.FieldU1("reserved_zero0")
}
showExistingFrame := d.FieldBool("show_existing_frame")
if showExistingFrame {
d.FieldU2("frame_to_show_map_idx")
return nil
}
frameType := d.FieldBool("frame_type", scalar.BoolMapSymStr{true: "non_key_frame", false: "key_frame"})
d.FieldU1("show_frame")
d.FieldU1("error_resilient_mode")
if !frameType {
// is key frame
vp9DecodeFrameSyncCode(d)
vp9DecodeColorConfig(d, profile)
vp9DecodeFrameSize(d)
}
d.FieldRawLen("data", d.BitsLeft())
return nil
}