Skip to content

Commit 9cf175e

Browse files
committed
Support FLV demuxer.
1 parent 17afed7 commit 9cf175e

File tree

4 files changed

+149
-1
lines changed

4 files changed

+149
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The core library including:
1818
- [x] [https](https/example_test.go): For https server over [lego/acme](https://github.com/xenolf/lego/tree/master/acme) of [letsencrypt](https://letsencrypt.org/).
1919
- [x] [gmoryx](gmoryx/README.md): A [gomobile](https://github.com/golang/mobile) API for go-oryx-lib.
2020
- [ ] [rtmp](rtmp/example_test.go): The RTMP protocol stack, for oryx.
21-
- [ ] [flv](flv/example_test.go): The FLV muxer, for oryx.
21+
- [ ] [flv](flv/example_test.go): The FLV muxer and demuxer, for oryx.
2222

2323
Other audio/video libraries:
2424

doc/video_file_format_spec_v10.pdf

203 KB
Binary file not shown.

flv/example_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,44 @@
2020
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2121

2222
package flv_test
23+
24+
import (
25+
"github.com/ossrs/go-oryx-lib/flv"
26+
"io"
27+
)
28+
29+
func ExampleDemuxer() {
30+
// To open a flv file, or http flv stream.
31+
var r io.Reader
32+
33+
f := flv.NewDemuxer(r)
34+
35+
var err error
36+
var version uint8
37+
var hasVideo, hasAudio bool
38+
if version, hasVideo, hasAudio, err = f.ReadHeader(); err != nil {
39+
return
40+
}
41+
42+
// Optional, user can check the header.
43+
_ = version
44+
_ = hasAudio
45+
_ = hasVideo
46+
47+
var tagType flv.TagType
48+
var tagSize, timestamp uint32
49+
if tagType, tagSize, timestamp, err = f.ReadTagHeader(); err != nil {
50+
return
51+
}
52+
53+
var tag []byte
54+
if tag, err = f.ReadTag(tagSize); err != nil {
55+
return
56+
}
57+
58+
// Using the FLV tag type, dts and body.
59+
// Refer to @doc video_file_format_spec_v10.pdf, @page 9, @section FLV tags
60+
_ = tagType
61+
_ = timestamp
62+
_ = tag
63+
}

flv/flv.go

+107
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,110 @@
2121

2222
// The oryx FLV package support bytes from/to FLV tags.
2323
package flv
24+
25+
import (
26+
"bytes"
27+
"errors"
28+
"io"
29+
)
30+
31+
// FLV Tag Type is the type of tag,
32+
// refer to @doc video_file_format_spec_v10.pdf, @page 9, @section FLV tags
33+
type TagType uint8
34+
35+
const (
36+
TagTypeForbidden TagType = 0
37+
TagTypeAudio TagType = 8
38+
TagTypeVideo TagType = 9
39+
TagTypeScriptData TagType = 18
40+
)
41+
42+
func (v TagType) String() string {
43+
switch v {
44+
case TagTypeVideo:
45+
return "Video"
46+
case TagTypeAudio:
47+
return "Audio"
48+
case TagTypeScriptData:
49+
return "Data"
50+
default:
51+
return "Forbidden"
52+
}
53+
}
54+
55+
// FLV Demuxer is used to demux FLV file.
56+
// Refer to @doc video_file_format_spec_v10.pdf, @page 7, @section The FLV File Format
57+
// A FLV file must consist the bellow parts:
58+
// 1. A FLV header, refer to @doc video_file_format_spec_v10.pdf, @page 8, @section The FLV header
59+
// 2. One or more tags, refer to @doc video_file_format_spec_v10.pdf, @page 9, @section FLV tags
60+
// @remark We always ignore the previous tag size.
61+
type Demuxer interface {
62+
// Read the FLV header, return the version of FLV, whether hasVideo or hasAudio in header.
63+
ReadHeader() (version uint8, hasVideo, hasAudio bool, err error)
64+
// Read the FLV tag header, return the tag information, especially the tag size,
65+
// then user can read the tag payload.
66+
ReadTagHeader() (tagType TagType, tagSize, timestamp uint32, err error)
67+
// Read the FLV tag body, drop the next 4 bytes previous tag size.
68+
ReadTag(tagSize uint32) (tag []byte, err error)
69+
}
70+
71+
// When FLV signature is not "FLV"
72+
var ErrSignature = errors.New("FLV signatures are illegal")
73+
74+
// Create a demuxer object.
75+
func NewDemuxer(r io.Reader) Demuxer {
76+
return &demuxer{
77+
r: r,
78+
}
79+
}
80+
81+
type demuxer struct {
82+
r io.Reader
83+
}
84+
85+
func (v *demuxer) ReadHeader() (version uint8, hasVideo, hasAudio bool, err error) {
86+
h := &bytes.Buffer{}
87+
if _, err = io.CopyN(h, v.r, 13); err != nil {
88+
return
89+
}
90+
91+
p := h.Bytes()
92+
93+
if !bytes.Equal([]byte{byte('F'), byte('L'), byte('V')}, p[:3]) {
94+
err = ErrSignature
95+
return
96+
}
97+
98+
version = uint8(p[3])
99+
hasVideo = (p[4] & 0x01) == 0x01
100+
hasAudio = ((p[4] >> 2) & 0x01) == 0x01
101+
102+
return
103+
}
104+
105+
func (v *demuxer) ReadTagHeader() (tagType TagType, tagSize uint32, timestamp uint32, err error) {
106+
h := &bytes.Buffer{}
107+
if _, err = io.CopyN(h, v.r, 11); err != nil {
108+
return
109+
}
110+
111+
p := h.Bytes()
112+
113+
tagType = TagType(p[0])
114+
tagSize = uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3])
115+
timestamp = uint32(p[7])<<24 | uint32(p[4])<<16 | uint32(p[5])<<8 | uint32(p[6])
116+
117+
return
118+
}
119+
120+
func (v *demuxer) ReadTag(tagSize uint32) (tag []byte, err error) {
121+
h := &bytes.Buffer{}
122+
if _, err = io.CopyN(h, v.r, int64(tagSize+4)); err != nil {
123+
return
124+
}
125+
126+
p := h.Bytes()
127+
tag = p[0 : len(p)-4]
128+
129+
return
130+
}

0 commit comments

Comments
 (0)