diff --git a/flv.go b/flv.go index a0df656..00eca33 100644 --- a/flv.go +++ b/flv.go @@ -14,6 +14,7 @@ import ( type Muxer struct { pw *pio.Writer + streams []av.CodecData } func NewMuxer(w io.Writer) *Muxer { @@ -22,6 +23,14 @@ func NewMuxer(w io.Writer) *Muxer { return self } +func Create(w io.Writer, streams []av.CodecData) (muxer *Muxer, err error) { + muxer = NewMuxer(w) + if err = muxer.WriteHeader(streams); err != nil { + return + } + return +} + func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { var flags uint8 for _, stream := range streams { @@ -36,6 +45,67 @@ func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { return } + for _, stream := range streams { + var _tag flvio.Tag + + switch stream.Type() { + case av.H264: + h264 := stream.(h264parser.CodecData) + tag := &flvio.Videodata{ + AVCPacketType: flvio.AVC_SEQHDR, + CodecID: flvio.VIDEO_H264, + Data: h264.AVCDecoderConfRecordBytes(), + } + _tag = tag + + case av.AAC: + aac := stream.(aacparser.CodecData) + tag := flvio.MakeAACAudiodata(aac, aac.MPEG4AudioConfigBytes()) + tag.AACPacketType = flvio.AAC_SEQHDR + _tag = &tag + + default: + err = fmt.Errorf("flv: unspported codecType=%v", stream.Type()) + return + } + + if err = flvio.WriteTag(self.pw, _tag, 0); err != nil { + return + } + } + + self.streams = streams + return +} + +func (self *Muxer) WritePacket(pkt av.Packet) (err error) { + stream := self.streams[pkt.Idx] + var _tag flvio.Tag + + switch stream.Type() { + case av.H264: + tag := &flvio.Videodata{ + AVCPacketType: flvio.AVC_NALU, + CodecID: flvio.VIDEO_H264, + Data: pkt.Data, + CompositionTime: timeToTs(pkt.CompositionTime), + } + if pkt.IsKeyFrame { + tag.FrameType = flvio.FRAME_KEY + } else { + tag.FrameType = flvio.FRAME_INTER + } + _tag = tag + + case av.AAC: + tag := flvio.MakeAACAudiodata(stream.(av.AudioCodecData), pkt.Data) + _tag = &tag + } + + if err = flvio.WriteTag(self.pw, _tag, timeToTs(pkt.Time)); err != nil { + return + } + return } @@ -138,6 +208,10 @@ func tsToTime(ts int32) time.Duration { return time.Millisecond*time.Duration(ts) } +func timeToTs(tm time.Duration) int32 { + return int32(tm / time.Millisecond) +} + func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) { var timestamp int32 var stream *flvStream diff --git a/flvio/flvio.go b/flvio/flvio.go index de5f462..19f6f7a 100644 --- a/flvio/flvio.go +++ b/flvio/flvio.go @@ -3,6 +3,7 @@ package flvio import ( "fmt" "github.com/nareix/pio" + "github.com/nareix/av" "io" ) @@ -64,6 +65,28 @@ const ( AAC_RAW = 1 ) +func MakeAACAudiodata(codec av.AudioCodecData, data []byte) Audiodata { + tag := Audiodata{ + SoundFormat: SOUND_AAC, + SoundRate: SOUND_44Khz, + AACPacketType: AAC_RAW, + Data: data, + } + switch codec.SampleFormat().BytesPerSample() { + case 1: + tag.SoundSize = SOUND_8BIT + default: + tag.SoundSize = SOUND_16BIT + } + switch codec.ChannelLayout().Count() { + case 1: + tag.SoundType = SOUND_MONO + case 2: + tag.SoundType = SOUND_STEREO + } + return tag +} + type Audiodata struct { /* SoundFormat: UB[4]