-
Notifications
You must be signed in to change notification settings - Fork 45
/
sidedata.go
276 lines (243 loc) · 8.52 KB
/
sidedata.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
package ffprobe
import (
"encoding/json"
"errors"
)
var (
ErrSideDataNotFound = errors.New("side data not found")
ErrSideDataUnexpectedType = errors.New("unexpected data type")
)
// All names and structures of side data types got from
// https://github.com/FFmpeg/FFmpeg/blob/4ab1184fae88bd47b9d195ac8224853c6f4e94cf/libavcodec/avpacket.c#L268
// https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffprobe.c#L2291
const (
SideDataTypeUnknown = "unknown"
SideDataTypeDisplayMatrix = "Display Matrix"
SideDataTypeStereo3D = "Stereo 3D"
SideDataTypeSphericalMapping = "Spherical Mapping"
SideDataTypeSkipSamples = "Skip Samples"
SideDataTypeMasteringDisplayMetadata = "Mastering display metadata"
SideDataTypeContentLightLevel = "Content light level metadata"
)
type SideDataBase struct {
Type string `json:"side_data_type"`
}
// SideDataDisplayMatrix represents the display matrix side data.
type SideDataDisplayMatrix struct {
SideDataBase
Data string `json:"displaymatrix"`
Rotation int `json:"rotation"`
}
// SideDataStereo3D represents the stereo 3D side data.
type SideDataStereo3D struct {
SideDataBase
Type string `json:"type"`
Inverted bool `json:"inverted"`
}
// SideDataSphericalMapping represents the spherical mapping side data.
type SideDataSphericalMapping struct {
SideDataBase
Projection string `json:"projection"`
Padding int `json:"padding,omitempty"`
BoundLeft int `json:"bound_left,omitempty"`
BoundTop int `json:"bound_top,omitempty"`
BoundRight int `json:"bound_right,omitempty"`
BoundBottom int `json:"bound_bottom,omitempty"`
Yaw int `json:"yaw,omitempty"`
Pitch int `json:"pitch,omitempty"`
Roll int `json:"roll,omitempty"`
}
// SideDataSkipSamples represents the skip samples side data.
type SideDataSkipSamples struct {
SideDataBase
SkipSamples int `json:"skip_samples"`
DiscardPadding int `json:"discard_padding"`
SkipReason int `json:"skip_reason"`
DiscardReason int `json:"discard_reason"`
}
// SideDataMasteringDisplayMetadata represents the mastering display metadata side data.
type SideDataMasteringDisplayMetadata struct {
SideDataBase
RedX int `json:"red_x,omitempty"`
RedY int `json:"red_y,omitempty"`
GreenX int `json:"green_x,omitempty"`
GreenY int `json:"green_y,omitempty"`
BlueX int `json:"blue_x,omitempty"`
BlueY int `json:"blue_y,omitempty"`
WhitePointX int `json:"white_point_x,omitempty"`
WhitePointY int `json:"white_point_y,omitempty"`
MinLuminance int `json:"min_luminance,omitempty"`
MaxLuminance int `json:"max_luminance,omitempty"`
}
// SideDataContentLightLevel represents the content light level side data.
type SideDataContentLightLevel struct {
SideDataBase
MaxContent int `json:"max_content,omitempty"`
MaxAverage int `json:"max_average,omitempty"`
}
// SideDataUnknown represents an unknown side data.
type SideDataUnknown Tags
// SideData represents a side data packet.
type SideData struct {
SideDataBase
Data interface{} `json:"-"`
}
func (sd *SideData) UnmarshalJSON(b []byte) error {
type Alias SideData
aux := &struct {
*Alias
}{
Alias: (*Alias)(sd),
}
if err := json.Unmarshal(b, aux); err != nil {
return err
}
switch sd.Type {
case SideDataTypeDisplayMatrix:
sd.Data = &SideDataDisplayMatrix{}
case SideDataTypeStereo3D:
sd.Data = new(SideDataStereo3D)
case SideDataTypeSphericalMapping:
sd.Data = new(SideDataSphericalMapping)
case SideDataTypeSkipSamples:
sd.Data = new(SideDataSkipSamples)
case SideDataTypeMasteringDisplayMetadata:
sd.Data = new(SideDataMasteringDisplayMetadata)
case SideDataTypeContentLightLevel:
sd.Data = new(SideDataContentLightLevel)
default:
sd.Data = new(SideDataUnknown)
}
return json.Unmarshal(b, sd.Data)
}
func (sd *SideData) MarshalJSON() ([]byte, error) {
return json.Marshal(sd.Data)
}
// SideDataList represents a list of side data packets.
type SideDataList []SideData
// UnmarshalJSON for SideDataList
func (s *SideDataList) UnmarshalJSON(b []byte) error {
var raw []json.RawMessage
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
for _, r := range raw {
var sd SideData
if err := json.Unmarshal(r, &sd); err != nil {
return err
}
*s = append(*s, sd)
}
return nil
}
// FindUnknownSideData searches for SideData of type SideDataUnknown in the SideDataList.
// If such SideData is found, it is returned, otherwise, an error is returned
// indicating that the SideData of type SideDataUnknown was not found or the found
// SideData was of an unexpected type.
func (s *SideDataList) FindUnknownSideData(sideDataType string) (*SideDataUnknown, error) {
data, found := s.findSideDataByName(sideDataType)
if !found {
return nil, ErrSideDataNotFound
}
unknownSideData, ok := data.(*SideDataUnknown)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return unknownSideData, nil
}
// FindSideData searches for SideData by its type in the SideDataList.
// If SideData of the specified type is found, it is returned, otherwise,
// an error is returned indicating that the SideData of the specified type was not found.
func (s *SideDataList) FindSideData(sideDataType string) (interface{}, error) {
data, found := s.findSideDataByName(sideDataType)
if !found {
return nil, ErrSideDataNotFound
}
return data, nil
}
// GetDisplayMatrix retrieves the DisplayMatrix from the SideData. If the DisplayMatrix is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetDisplayMatrix() (*SideDataDisplayMatrix, error) {
data, found := s.findSideDataByName(SideDataTypeDisplayMatrix)
if !found {
return nil, ErrSideDataNotFound
}
displayMatrix, ok := data.(*SideDataDisplayMatrix)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return displayMatrix, nil
}
// GetStereo3D retrieves the Stereo3D data from the SideData. If the Stereo3D data is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetStereo3D() (*SideDataStereo3D, error) {
data, found := s.findSideDataByName(SideDataTypeStereo3D)
if !found {
return nil, ErrSideDataNotFound
}
stereo3D, ok := data.(*SideDataStereo3D)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return stereo3D, nil
}
// GetSphericalMapping retrieves the SphericalMapping data from the SideData. If the SphericalMapping data is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetSphericalMapping() (*SideDataSphericalMapping, error) {
data, found := s.findSideDataByName(SideDataTypeSphericalMapping)
if !found {
return nil, ErrSideDataNotFound
}
sphericalMapping, ok := data.(*SideDataSphericalMapping)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return sphericalMapping, nil
}
// GetSkipSamples retrieves the SkipSamples data from the SideData. If the SkipSamples data is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetSkipSamples() (*SideDataSkipSamples, error) {
data, found := s.findSideDataByName(SideDataTypeSkipSamples)
if !found {
return nil, ErrSideDataNotFound
}
skipSamples, ok := data.(*SideDataSkipSamples)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return skipSamples, nil
}
// GetMasteringDisplayMetadata retrieves the MasteringDisplayMetadata from the SideData. If the MasteringDisplayMetadata is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetMasteringDisplayMetadata() (*SideDataMasteringDisplayMetadata, error) {
data, found := s.findSideDataByName(SideDataTypeMasteringDisplayMetadata)
if !found {
return nil, ErrSideDataNotFound
}
masteringDisplayMetadata, ok := data.(*SideDataMasteringDisplayMetadata)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return masteringDisplayMetadata, nil
}
// GetContentLightLevel retrieves the ContentLightLevel from the SideData. If the ContentLightLevel is not found or
// the SideData is of the wrong type, an error is returned.
func (s *SideDataList) GetContentLightLevel() (*SideDataContentLightLevel, error) {
data, found := s.findSideDataByName(SideDataTypeContentLightLevel)
if !found {
return nil, ErrSideDataNotFound
}
contentLightLevel, ok := data.(*SideDataContentLightLevel)
if !ok {
return nil, ErrSideDataUnexpectedType
}
return contentLightLevel, nil
}
func (s *SideDataList) findSideDataByName(sideDataType string) (interface{}, bool) {
for _, sd := range *s {
if sd.Type == sideDataType {
return sd.Data, true
}
}
return nil, false
}