change flvio.Tag from interface to struct

This commit is contained in:
nareix 2016-09-19 07:29:56 +08:00
parent a76cfa1413
commit b3b189ca28
3 changed files with 287 additions and 333 deletions

View File

@ -1,17 +1,17 @@
package flv package flv
import ( import (
"bufio"
"fmt" "fmt"
"github.com/nareix/bits/pio"
"github.com/nareix/joy4/av" "github.com/nareix/joy4/av"
"github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/av/avutil"
"github.com/nareix/joy4/codec/h264parser"
"github.com/nareix/joy4/codec" "github.com/nareix/joy4/codec"
"github.com/nareix/joy4/codec/fake"
"github.com/nareix/joy4/codec/aacparser" "github.com/nareix/joy4/codec/aacparser"
"github.com/nareix/bits/pio" "github.com/nareix/joy4/codec/fake"
"github.com/nareix/joy4/codec/h264parser"
"github.com/nareix/joy4/format/flv/flvio" "github.com/nareix/joy4/format/flv/flvio"
"io" "io"
"bufio"
) )
var MaxProbePacketCount = 20 var MaxProbePacketCount = 20
@ -73,7 +73,7 @@ func (self *Prober) CacheTag(_tag flvio.Tag, timestamp int32) {
self.CachedPkts = append(self.CachedPkts, pkt) self.CachedPkts = append(self.CachedPkts, pkt)
} }
func (self *Prober) PushTag(_tag flvio.Tag, timestamp int32) (err error) { func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
self.PushedCount++ self.PushedCount++
if self.PushedCount > MaxProbePacketCount { if self.PushedCount > MaxProbePacketCount {
@ -81,8 +81,8 @@ func (self *Prober) PushTag(_tag flvio.Tag, timestamp int32) (err error) {
return return
} }
switch tag := _tag.(type) { switch tag.Type {
case *flvio.Videodata: case flvio.TAG_VIDEO:
switch tag.AVCPacketType { switch tag.AVCPacketType {
case flvio.AVC_SEQHDR: case flvio.AVC_SEQHDR:
if !self.GotVideo { if !self.GotVideo {
@ -100,7 +100,7 @@ func (self *Prober) PushTag(_tag flvio.Tag, timestamp int32) (err error) {
self.CacheTag(tag, timestamp) self.CacheTag(tag, timestamp)
} }
case *flvio.Audiodata: case flvio.TAG_AUDIO:
switch tag.SoundFormat { switch tag.SoundFormat {
case flvio.SOUND_AAC: case flvio.SOUND_AAC:
switch tag.AACPacketType { switch tag.AACPacketType {
@ -162,9 +162,9 @@ func (self *Prober) Probed() (ok bool) {
return return
} }
func (self *Prober) TagToPacket(_tag flvio.Tag, timestamp int32) (pkt av.Packet, ok bool) { func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, ok bool) {
switch tag := _tag.(type) { switch tag.Type {
case *flvio.Videodata: case flvio.TAG_VIDEO:
pkt.Idx = int8(self.VideoStreamIdx) pkt.Idx = int8(self.VideoStreamIdx)
switch tag.AVCPacketType { switch tag.AVCPacketType {
case flvio.AVC_NALU: case flvio.AVC_NALU:
@ -174,7 +174,7 @@ func (self *Prober) TagToPacket(_tag flvio.Tag, timestamp int32) (pkt av.Packet,
pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY
} }
case *flvio.Audiodata: case flvio.TAG_AUDIO:
pkt.Idx = int8(self.AudioStreamIdx) pkt.Idx = int8(self.AudioStreamIdx)
switch tag.SoundFormat { switch tag.SoundFormat {
case flvio.SOUND_AAC: case flvio.SOUND_AAC:
@ -212,7 +212,8 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
switch stream.Type() { switch stream.Type() {
case av.H264: case av.H264:
h264 := stream.(h264parser.CodecData) h264 := stream.(h264parser.CodecData)
tag := &flvio.Videodata{ tag := flvio.Tag{
Type: flvio.TAG_VIDEO,
AVCPacketType: flvio.AVC_SEQHDR, AVCPacketType: flvio.AVC_SEQHDR,
CodecID: flvio.VIDEO_H264, CodecID: flvio.VIDEO_H264,
Data: h264.AVCDecoderConfRecordBytes(), Data: h264.AVCDecoderConfRecordBytes(),
@ -226,7 +227,8 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
case av.AAC: case av.AAC:
aac := stream.(aacparser.CodecData) aac := stream.(aacparser.CodecData)
tag := &flvio.Audiodata{ tag := flvio.Tag{
Type: flvio.TAG_AUDIO,
SoundFormat: flvio.SOUND_AAC, SoundFormat: flvio.SOUND_AAC,
SoundRate: flvio.SOUND_44Khz, SoundRate: flvio.SOUND_44Khz,
AACPacketType: flvio.AAC_SEQHDR, AACPacketType: flvio.AAC_SEQHDR,
@ -254,10 +256,11 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
return return
} }
func PacketToTag(pkt av.Packet, stream av.CodecData) (_tag flvio.Tag, timestamp int32) { func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, timestamp int32) {
switch stream.Type() { switch stream.Type() {
case av.H264: case av.H264:
tag := &flvio.Videodata{ tag = flvio.Tag{
Type: flvio.TAG_VIDEO,
AVCPacketType: flvio.AVC_NALU, AVCPacketType: flvio.AVC_NALU,
CodecID: flvio.VIDEO_H264, CodecID: flvio.VIDEO_H264,
Data: pkt.Data, Data: pkt.Data,
@ -268,10 +271,10 @@ func PacketToTag(pkt av.Packet, stream av.CodecData) (_tag flvio.Tag, timestamp
} else { } else {
tag.FrameType = flvio.FRAME_INTER tag.FrameType = flvio.FRAME_INTER
} }
_tag = tag
case av.AAC: case av.AAC:
tag := &flvio.Audiodata{ tag = flvio.Tag{
Type: flvio.TAG_AUDIO,
SoundFormat: flvio.SOUND_AAC, SoundFormat: flvio.SOUND_AAC,
SoundRate: flvio.SOUND_44Khz, SoundRate: flvio.SOUND_44Khz,
AACPacketType: flvio.AAC_RAW, AACPacketType: flvio.AAC_RAW,
@ -290,21 +293,20 @@ func PacketToTag(pkt av.Packet, stream av.CodecData) (_tag flvio.Tag, timestamp
case 2: case 2:
tag.SoundType = flvio.SOUND_STEREO tag.SoundType = flvio.SOUND_STEREO
} }
_tag = tag
case av.SPEEX: case av.SPEEX:
tag := &flvio.Audiodata{ tag = flvio.Tag{
Type: flvio.TAG_AUDIO,
SoundFormat: flvio.SOUND_SPEEX, SoundFormat: flvio.SOUND_SPEEX,
Data: pkt.Data, Data: pkt.Data,
} }
_tag = tag
case av.NELLYMOSER: case av.NELLYMOSER:
tag := &flvio.Audiodata{ tag = flvio.Tag{
Type: flvio.TAG_AUDIO,
SoundFormat: flvio.SOUND_NELLYMOSER, SoundFormat: flvio.SOUND_NELLYMOSER,
Data: pkt.Data, Data: pkt.Data,
} }
_tag = tag
} }
timestamp = flvio.TimeToTs(pkt.Time) timestamp = flvio.TimeToTs(pkt.Time)
@ -490,4 +492,3 @@ func Handler(h *avutil.RegisterHandler) {
h.CodecTypes = CodecTypes h.CodecTypes = CodecTypes
} }

View File

@ -1,11 +1,11 @@
package flvio package flvio
import ( import (
"io"
"time"
"fmt" "fmt"
"github.com/nareix/bits/pio" "github.com/nareix/bits/pio"
"github.com/nareix/joy4/av" "github.com/nareix/joy4/av"
"io"
"time"
) )
func TsToTime(ts int32) time.Duration { func TsToTime(ts int32) time.Duration {
@ -16,46 +16,14 @@ func TimeToTs(tm time.Duration) int32 {
return int32(tm / time.Millisecond) return int32(tm / time.Millisecond)
} }
const MaxTagSubHeaderLength = 16
const ( const (
TAG_AUDIO = 8 TAG_AUDIO = 8
TAG_VIDEO = 9 TAG_VIDEO = 9
TAG_SCRIPTDATA = 18 TAG_SCRIPTDATA = 18
) )
const MaxTagSubHeaderLength = 16
type Tag interface {
Type() uint8
GetData() []byte
SetData([]byte)
FillHeader([]byte) int
ParseHeader([]byte) (int,error)
}
type Scriptdata struct {
Data []byte
}
func (self Scriptdata) Type() uint8 {
return TAG_SCRIPTDATA
}
func (self *Scriptdata) FillHeader(b []byte) (n int) {
return
}
func (self *Scriptdata) ParseHeader(b []byte) (n int, err error) {
return
}
func (self Scriptdata) GetData() []byte {
return self.Data
}
func (self *Scriptdata) SetData(b []byte) {
self.Data = b
}
const ( const (
SOUND_MP3 = 2 SOUND_MP3 = 2
SOUND_NELLYMOSER_16KHZ_MONO = 4 SOUND_NELLYMOSER_16KHZ_MONO = 4
@ -81,7 +49,20 @@ const (
AAC_RAW = 1 AAC_RAW = 1
) )
type Audiodata struct { const (
AVC_SEQHDR = 0
AVC_NALU = 1
AVC_EOS = 2
FRAME_KEY = 1
FRAME_INTER = 2
VIDEO_H264 = 7
)
type Tag struct {
Type uint8
/* /*
SoundFormat: UB[4] SoundFormat: UB[4]
0 = Linear PCM, platform endian 0 = Linear PCM, platform endian
@ -139,85 +120,6 @@ type Audiodata struct {
*/ */
AACPacketType uint8 AACPacketType uint8
Data []byte
}
func (self Audiodata) Type() uint8 {
return TAG_AUDIO
}
func (self Audiodata) ChannelLayout() av.ChannelLayout {
if self.SoundType == SOUND_MONO {
return av.CH_MONO
} else {
return av.CH_STEREO
}
}
func (self *Audiodata) ParseHeader(b []byte) (n int, err error) {
if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid")
return
}
flags := b[n]
n++
self.SoundFormat = flags >> 4
self.SoundRate = (flags >> 2) & 0x3
self.SoundSize = (flags >> 1) & 0x1
self.SoundType = flags & 0x1
switch self.SoundFormat {
case SOUND_AAC:
if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid")
return
}
self.AACPacketType = b[n]
n++
}
return
}
func (self Audiodata) FillHeader(b []byte) (n int) {
var flags uint8
flags |= self.SoundFormat << 4
flags |= self.SoundRate << 2
flags |= self.SoundSize << 1
flags |= self.SoundType
b[n] = flags
n++
switch self.SoundFormat {
case SOUND_AAC:
b[n] = self.AACPacketType
n++
}
return
}
func (self Audiodata) GetData() []byte {
return self.Data
}
func (self *Audiodata) SetData(b []byte) {
self.Data = b
}
const (
AVC_SEQHDR = 0
AVC_NALU = 1
AVC_EOS = 2
FRAME_KEY = 1
FRAME_INTER = 2
VIDEO_H264 = 7
)
type Videodata struct {
/* /*
1: keyframe (for AVC, a seekable frame) 1: keyframe (for AVC, a seekable frame)
2: inter frame (for AVC, a non- seekable frame) 2: inter frame (for AVC, a non- seekable frame)
@ -245,15 +147,64 @@ type Videodata struct {
*/ */
AVCPacketType uint8 AVCPacketType uint8
Data []byte
CompositionTime int32 CompositionTime int32
Data []byte
} }
func (self Videodata) Type() uint8 { func (self Tag) ChannelLayout() av.ChannelLayout {
return TAG_VIDEO if self.SoundType == SOUND_MONO {
return av.CH_MONO
} else {
return av.CH_STEREO
}
} }
func (self *Videodata) ParseHeader(b []byte) (n int, err error) { func (self *Tag) audioParseHeader(b []byte) (n int, err error) {
if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid")
return
}
flags := b[n]
n++
self.SoundFormat = flags >> 4
self.SoundRate = (flags >> 2) & 0x3
self.SoundSize = (flags >> 1) & 0x1
self.SoundType = flags & 0x1
switch self.SoundFormat {
case SOUND_AAC:
if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid")
return
}
self.AACPacketType = b[n]
n++
}
return
}
func (self Tag) audioFillHeader(b []byte) (n int) {
var flags uint8
flags |= self.SoundFormat << 4
flags |= self.SoundRate << 2
flags |= self.SoundSize << 1
flags |= self.SoundType
b[n] = flags
n++
switch self.SoundFormat {
case SOUND_AAC:
b[n] = self.AACPacketType
n++
}
return
}
func (self *Tag) videoParseHeader(b []byte) (n int, err error) {
if len(b) < n+1 { if len(b) < n+1 {
err = fmt.Errorf("videodata: parse invalid") err = fmt.Errorf("videodata: parse invalid")
return return
@ -278,7 +229,7 @@ func (self *Videodata) ParseHeader(b []byte) (n int, err error) {
return return
} }
func (self Videodata) FillHeader(b []byte) (n int) { func (self Tag) videoFillHeader(b []byte) (n int) {
flags := self.FrameType<<4 | self.CodecID flags := self.FrameType<<4 | self.CodecID
b[n] = flags b[n] = flags
n++ n++
@ -289,12 +240,28 @@ func (self Videodata) FillHeader(b []byte) (n int) {
return return
} }
func (self Videodata) GetData() []byte { func (self Tag) FillHeader(b []byte) (n int) {
return self.Data switch self.Type {
case TAG_AUDIO:
return self.audioFillHeader(b)
case TAG_VIDEO:
return self.videoFillHeader(b)
} }
func (self *Videodata) SetData(b []byte) { return
self.Data = b }
func (self *Tag) ParseHeader(b []byte) (n int, err error) {
switch self.Type {
case TAG_AUDIO:
return self.audioParseHeader(b)
case TAG_VIDEO:
return self.videoParseHeader(b)
}
return
} }
const ( const (
@ -313,14 +280,8 @@ func ParseTagHeader(b []byte) (tag Tag, ts int32, datalen int, err error) {
tagtype := b[0] tagtype := b[0]
switch tagtype { switch tagtype {
case TAG_AUDIO: case TAG_AUDIO, TAG_VIDEO, TAG_SCRIPTDATA:
tag = &Audiodata{} tag = Tag{Type: tagtype}
case TAG_VIDEO:
tag = &Videodata{}
case TAG_SCRIPTDATA:
tag = &Scriptdata{}
default: default:
err = fmt.Errorf("flvio: ReadTag tagtype=%d invalid", tagtype) err = fmt.Errorf("flvio: ReadTag tagtype=%d invalid", tagtype)
@ -353,10 +314,10 @@ func ReadTag(r io.Reader, b []byte) (tag Tag, ts int32, err error) {
} }
var n int var n int
if n, err = tag.ParseHeader(data); err != nil { if n, err = (&tag).ParseHeader(data); err != nil {
return return
} }
tag.SetData(data[n:]) tag.Data = data[n:]
if _, err = io.ReadFull(r, b[:4]); err != nil { if _, err = io.ReadFull(r, b[:4]); err != nil {
return return
@ -385,12 +346,12 @@ func FillTagTrailer(b []byte, datalen int) (n int) {
} }
func WriteTag(w io.Writer, tag Tag, ts int32, b []byte) (err error) { func WriteTag(w io.Writer, tag Tag, ts int32, b []byte) (err error) {
data := tag.GetData() data := tag.Data
n := tag.FillHeader(b[TagHeaderLength:]) n := tag.FillHeader(b[TagHeaderLength:])
datalen := len(data) + n datalen := len(data) + n
n += FillTagHeader(b, tag.Type(), datalen, ts) n += FillTagHeader(b, tag.Type, datalen, ts)
if _, err = w.Write(b[:n]); err != nil { if _, err = w.Write(b[:n]); err != nil {
return return
@ -447,5 +408,3 @@ func ParseFileHeader(b []byte) (flags uint8, skip int, err error) {
return return
} }

View File

@ -1,24 +1,23 @@
package rtmp package rtmp
import ( import (
"strings"
"bytes"
"net"
"net/url"
"bufio" "bufio"
"time" "bytes"
"fmt" "crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/hex" "encoding/hex"
"io" "fmt"
"github.com/nareix/bits/pio" "github.com/nareix/bits/pio"
"github.com/nareix/joy4/format/flv"
"github.com/nareix/joy4/format/flv/flvio"
"github.com/nareix/joy4/av" "github.com/nareix/joy4/av"
"github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/av/avutil"
"crypto/hmac" "github.com/nareix/joy4/format/flv"
"crypto/sha256" "github.com/nareix/joy4/format/flv/flvio"
"crypto/rand" "io"
"net"
"net/url"
"strings"
"time"
) )
var Debug bool var Debug bool
@ -148,6 +147,7 @@ type Conn struct {
bufr *bufio.Reader bufr *bufio.Reader
bufw *bufio.Writer bufw *bufio.Writer
ackn uint32 ackn uint32
writebuf []byte writebuf []byte
readbuf []byte readbuf []byte
@ -177,8 +177,7 @@ type Conn struct {
msgdata []byte msgdata []byte
msgtypeid uint8 msgtypeid uint8
datamsgvals []interface{} datamsgvals []interface{}
videodata *flvio.Videodata avtag flvio.Tag
audiodata *flvio.Audiodata
eventtype uint16 eventtype uint16
} }
@ -286,11 +285,8 @@ func (self *Conn) pollAVTag() (tag flvio.Tag, err error) {
return return
} }
switch self.msgtypeid { switch self.msgtypeid {
case msgtypeidVideoMsg: case msgtypeidVideoMsg, msgtypeidAudioMsg:
tag = self.videodata tag = self.avtag
return
case msgtypeidAudioMsg:
tag = self.audiodata
return return
} }
} }
@ -300,8 +296,7 @@ func (self *Conn) pollMsg() (err error) {
self.gotmsg = false self.gotmsg = false
self.gotcommand = false self.gotcommand = false
self.datamsgvals = nil self.datamsgvals = nil
self.videodata = nil self.avtag = flvio.Tag{}
self.audiodata = nil
for { for {
if err = self.readChunk(); err != nil { if err = self.readChunk(); err != nil {
return return
@ -479,8 +474,8 @@ func (self *Conn) readConnect() (err error) {
"onStatus", self.commandtransid, nil, "onStatus", self.commandtransid, nil,
flvio.AMFMap{ flvio.AMFMap{
"level": "status", "level": "status",
"code": code, "code": "NetStream.Publish.Start",
"description": description, "description": "Start publishing",
}, },
); err != nil { ); err != nil {
return return
@ -1003,16 +998,16 @@ func (self *Conn) writeAVTag(tag flvio.Tag, ts int32) (err error) {
var csid uint32 var csid uint32
var data []byte var data []byte
switch _tag := tag.(type) { switch tag.Type {
case *flvio.Audiodata: case flvio.TAG_AUDIO:
msgtypeid = msgtypeidAudioMsg msgtypeid = msgtypeidAudioMsg
csid = 6 csid = 6
data = _tag.Data data = tag.Data
case *flvio.Videodata: case flvio.TAG_VIDEO:
msgtypeid = msgtypeidVideoMsg msgtypeid = msgtypeidVideoMsg
csid = 7 csid = 7
data = _tag.Data data = tag.Data
} }
b := self.tmpwbuf(chunkHeaderLength + flvio.MaxTagSubHeaderLength) b := self.tmpwbuf(chunkHeaderLength + flvio.MaxTagSubHeaderLength)
@ -1408,28 +1403,28 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms
if len(msgdata) == 0 { if len(msgdata) == 0 {
return return
} }
tag := &flvio.Videodata{} tag := flvio.Tag{Type: flvio.TAG_VIDEO}
var n int var n int
if n, err = tag.ParseHeader(msgdata); err != nil { if n, err = (&tag).ParseHeader(msgdata); err != nil {
return return
} }
if !(tag.FrameType == flvio.FRAME_INTER || tag.FrameType == flvio.FRAME_KEY) { if !(tag.FrameType == flvio.FRAME_INTER || tag.FrameType == flvio.FRAME_KEY) {
return return
} }
tag.Data = msgdata[n:] tag.Data = msgdata[n:]
self.videodata = tag self.avtag = tag
case msgtypeidAudioMsg: case msgtypeidAudioMsg:
if len(msgdata) == 0 { if len(msgdata) == 0 {
return return
} }
tag := &flvio.Audiodata{} tag := flvio.Tag{Type: flvio.TAG_AUDIO}
var n int var n int
if n, err = tag.ParseHeader(msgdata); err != nil { if n, err = (&tag).ParseHeader(msgdata); err != nil {
return return
} }
tag.Data = msgdata[n:] tag.Data = msgdata[n:]
self.audiodata = tag self.avtag = tag
case msgtypeidSetChunkSize: case msgtypeidSetChunkSize:
if len(msgdata) < 4 { if len(msgdata) < 4 {
@ -1749,4 +1744,3 @@ func Handler(h *avutil.RegisterHandler) {
h.CodecTypes = CodecTypes h.CodecTypes = CodecTypes
} }