av/stream/flv/flv.go

159 lines
3.7 KiB
Go
Raw Normal View History

/*
NAME
flv.go
DESCRIPTION
See Readme.md
AUTHORS
Saxon A. Nelson-Milton <saxon@ausocean.org>
2018-07-07 08:57:59 +03:00
Dan Kortschak <dan@ausocean.org>
LICENSE
flv.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
2018-07-07 08:57:59 +03:00
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
2018-07-07 08:57:59 +03:00
// See https://wwwimages2.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf
// for format specification.
2018-02-10 16:25:55 +03:00
package flv
2018-07-07 08:57:59 +03:00
import "encoding/binary"
2018-05-30 10:19:13 +03:00
2018-02-10 16:25:55 +03:00
const (
maxVideoTagSize = 10000
maxAudioTagSize = 10000
)
const (
VideoTagType = 9
AudioTagType = 8
KeyFrameType = 1
InterFrameType = 2
H264 = 7
AVCNALU = 1
SequenceHeader = 0
DataHeaderLength = 5
NoTimestampExtension = 0
AACAudioFormat = 10
PCMAudioFormat = 0
2018-02-10 16:25:55 +03:00
)
2018-07-07 08:57:59 +03:00
const (
sizeofFLVTagHeader = 11
sizeofPrevTagSize = 4
)
const version = 0x01
// FLV is big-endian.
var order = binary.BigEndian
// orderPutUint24 is a binary.BigEndian method look-alike for
// writing 24 bit words to a byte slice.
func orderPutUint24(b []byte, v uint32) {
_ = b[2] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 16)
b[1] = byte(v >> 8)
b[2] = byte(v)
}
var flvHeaderCode = []byte{'F', 'L', 'V', version}
2018-02-10 16:25:55 +03:00
type Header struct {
2018-07-07 08:57:59 +03:00
HasAudio bool
HasVideo bool
2018-02-10 16:25:55 +03:00
}
2018-07-07 08:57:59 +03:00
func (h *Header) Bytes() []byte {
const headerLength = 9
b := [headerLength]byte{
0: 'F', 1: 'L', 2: 'V', 3: version,
4: btb(h.HasAudio)<<2 | btb(h.HasVideo),
8: headerLength, // order.PutUint32(b[5:9], headerLength)
}
return b[:]
}
type VideoTag struct {
TagType uint8
DataSize uint32
Timestamp uint32
TimestampExtended uint8
FrameType uint8
Codec uint8
PacketType uint8
CompositionTime uint32
Data []byte
PrevTagSize uint32
}
func (t *VideoTag) Bytes() []byte {
// FIXME(kortschak): This should probably be an encoding.BinaryMarshaler.
// This will allow handling of invalid field values.
b := make([]byte, t.DataSize+sizeofFLVTagHeader+sizeofPrevTagSize)
b[0] = t.TagType
orderPutUint24(b[1:4], t.DataSize)
orderPutUint24(b[4:7], t.Timestamp)
b[7] = t.TimestampExtended
b[11] = t.FrameType<<4 | t.Codec
b[12] = t.PacketType
orderPutUint24(b[13:16], t.CompositionTime)
copy(b[16:], t.Data)
order.PutUint32(b[len(b)-4:], t.PrevTagSize)
return b
}
type AudioTag struct {
TagType uint8
DataSize uint32
Timestamp uint32
TimestampExtended uint8
SoundFormat uint8
SoundRate uint8
SoundSize bool
SoundType bool
Data []byte
PrevTagSize uint32
}
2018-07-07 08:57:59 +03:00
func (t *AudioTag) Bytes() []byte {
// FIXME(kortschak): This should probably be an encoding.BinaryMarshaler.
// This will allow handling of invalid field values.
b := make([]byte, t.DataSize+sizeofFLVTagHeader+sizeofPrevTagSize)
b[0] = t.TagType
orderPutUint24(b[1:4], t.DataSize)
orderPutUint24(b[4:7], t.Timestamp)
b[7] = t.TimestampExtended
b[11] = t.SoundFormat<<4 | t.SoundRate<<2 | btb(t.SoundSize)<<1 | btb(t.SoundType)
copy(b[12:], t.Data)
order.PutUint32(b[len(b)-4:], t.PrevTagSize)
return b
}
func btb(b bool) byte {
if b {
return 1
}
return 0
2018-02-10 16:25:55 +03:00
}