forked from 32bitkid/mpeg
/
video_sequence.go
99 lines (84 loc) · 2.23 KB
/
video_sequence.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
package video
import "io"
import "image"
import "github.com/32bitkid/bitreader"
type sequenceHeaders struct {
*SequenceHeader
*SequenceExtension
}
type pictureHeaders struct {
*GroupOfPicturesHeader
*PictureHeader
*PictureCodingExtension
}
type VideoSequence struct {
bitreader.BitReader
sequenceHeaders
pictureHeaders
quantisationMatricies [4]quantisationMatrix
frameStore
frameCounter uint32
}
func NewVideoSequence(r io.Reader) *VideoSequence {
return &VideoSequence{
BitReader: bitreader.NewReader(r),
}
}
// AlignTo will trash all bits until the stream is aligned with the desired start code or error is produced.
func (br *VideoSequence) AlignTo(startCode StartCode) error {
if !br.IsAligned() {
if _, err := br.Align(); err != nil {
return err
}
}
for {
if val, err := br.Peek32(32); err != nil {
return err
} else if StartCode(val) == startCode {
return nil
} else if err := br.Skip(8); err != nil {
return err
}
}
}
func (vs *VideoSequence) sequence_extension() (err error) {
vs.SequenceExtension, err = sequence_extension(vs)
return
}
func (vs *VideoSequence) picture_header() (err error) {
vs.PictureHeader, err = picture_header(vs)
return
}
func (vs *VideoSequence) picture_coding_extension() (err error) {
vs.PictureCodingExtension, err = picture_coding_extension(vs)
return
}
func (vs *VideoSequence) Size() (width int, height int) {
if vs.SequenceHeader == nil {
return -1, -1
}
width = int(vs.SequenceHeader.horizontal_size_value)
height = int(vs.SequenceHeader.vertical_size_value)
if vs.SequenceExtension != nil {
width |= int(vs.SequenceExtension.horizontal_size_extension << 12)
height |= int(vs.SequenceExtension.vertical_size_extension << 12)
}
return
}
// Next() will return the next frame of video decoded from the video stream.
func (vs *VideoSequence) Next() (*image.YCbCr, error) {
// Try to get a previously decoded frame out of the frameStore.
if img := vs.frameStore.tryGet(vs.frameCounter); img != nil {
vs.frameCounter++
return img, nil
}
// Step until a temporal match is found.
for {
if img, err := vs.step(); err != nil {
return nil, err
} else if vs.PictureHeader.temporal_reference == vs.frameCounter {
vs.frameCounter++
return img, nil
}
}
}