From e3a02beada80383d39ff5e8b5154a9b14af703ee Mon Sep 17 00:00:00 2001 From: nareix Date: Wed, 13 Jul 2016 15:11:11 +0800 Subject: [PATCH] add SPEEX codec --- cgo/ffmpeg/audio.go | 17 ++++++++++++++--- codec/codec.go | 21 +++++++++++++++++---- codec/fake/fake.go | 19 +++++++++++++++++-- format/flv/flv.go | 14 +++++++++++--- format/flv/flvio/flvio.go | 9 +++++++++ format/rtmp/rtmp.go | 2 +- 6 files changed, 69 insertions(+), 13 deletions(-) diff --git a/cgo/ffmpeg/audio.go b/cgo/ffmpeg/audio.go index f462f58..e5efabf 100644 --- a/cgo/ffmpeg/audio.go +++ b/cgo/ffmpeg/audio.go @@ -617,6 +617,9 @@ func NewAudioDecoder(codec av.AudioCodecData) (dec *AudioDecoder, err error) { return } + case av.SPEEX: + id = C.AV_CODEC_ID_SPEEX + case av.PCM_MULAW: id = C.AV_CODEC_ID_PCM_MULAW @@ -680,17 +683,25 @@ func (self audioCodecData) ChannelLayout() av.ChannelLayout { } func (self audioCodecData) PacketDuration(data []byte) (dur time.Duration, err error) { - // TODO: implement it + // TODO: implement it: ffmpeg get_audio_frame_duration err = fmt.Errorf("ffmpeg: cannot get packet duration") return } func AudioCodecHandler(h *avutil.RegisterHandler) { h.AudioDecoder = func(codec av.AudioCodecData) (av.AudioDecoder, error) { - return NewAudioDecoder(codec) + if dec, err := NewAudioDecoder(codec); err != nil { + return nil, nil + } else { + return dec, err + } } h.AudioEncoder = func(typ av.CodecType) (av.AudioEncoder, error) { - return NewAudioEncoderByCodecType(typ) + if enc, err := NewAudioEncoderByCodecType(typ); err != nil { + return nil, nil + } else { + return enc, err + } } } diff --git a/codec/codec.go b/codec/codec.go index e5724ce..d37df77 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -2,6 +2,7 @@ package codec import ( "github.com/nareix/joy4/av" + "github.com/nareix/joy4/codec/fake" "time" ) @@ -41,11 +42,23 @@ func NewPCMAlawCodecData() av.AudioCodecData { } } -func NewNellyMoserCodecData() av.AudioCodecData { - return PCMUCodecData{typ: av.NELLYMOSER} +type SpeexCodecData struct { + fake.CodecData } -func NewSpeexCodecData() av.AudioCodecData { - return PCMUCodecData{typ: av.SPEEX} +func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration, error) { + // libavcodec/libspeexdec.c + // samples = samplerate/50 + // duration = 0.02s + return time.Millisecond*20, nil +} + +func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData { + codec := SpeexCodecData{} + codec.CodecType_ = av.SPEEX + codec.SampleFormat_ = av.S16 + codec.SampleRate_ = sr + codec.ChannelLayout_ = cl + return codec } diff --git a/codec/fake/fake.go b/codec/fake/fake.go index 1c121d9..51e056f 100644 --- a/codec/fake/fake.go +++ b/codec/fake/fake.go @@ -5,10 +5,25 @@ import ( ) type CodecData struct { - Typ av.CodecType + CodecType_ av.CodecType + SampleRate_ int + SampleFormat_ av.SampleFormat + ChannelLayout_ av.ChannelLayout } func (self CodecData) Type() av.CodecType { - return self.Typ + return self.CodecType_ +} + +func (self CodecData) SampleFormat() av.SampleFormat { + return self.SampleFormat_ +} + +func (self CodecData) ChannelLayout() av.ChannelLayout { + return self.ChannelLayout_ +} + +func (self CodecData) SampleRate() int { + return self.SampleRate_ } diff --git a/format/flv/flv.go b/format/flv/flv.go index e6d85dc..8192350 100644 --- a/format/flv/flv.go +++ b/format/flv/flv.go @@ -6,6 +6,7 @@ import ( "github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/codec/h264parser" "github.com/nareix/joy4/codec" + "github.com/nareix/joy4/codec/fake" "github.com/nareix/joy4/codec/aacparser" "github.com/nareix/pio" "github.com/nareix/joy4/format/flv/flvio" @@ -78,7 +79,7 @@ func (self *Prober) PushTag(_tag flvio.Tag, timestamp int32) (err error) { case flvio.SOUND_SPEEX: if !self.GotAudio { - stream := codec.NewSpeexCodecData() + stream := codec.NewSpeexCodecData(16000, tag.ChannelLayout()) self.AudioStreamIdx = len(self.Streams) self.Streams = append(self.Streams, stream) self.GotAudio = true @@ -87,7 +88,12 @@ func (self *Prober) PushTag(_tag flvio.Tag, timestamp int32) (err error) { case flvio.SOUND_NELLYMOSER: if !self.GotAudio { - stream := codec.NewNellyMoserCodecData() + stream := fake.CodecData{ + CodecType_: av.NELLYMOSER, + SampleRate_: 16000, + SampleFormat_: av.S16, + ChannelLayout_: tag.ChannelLayout(), + } self.AudioStreamIdx = len(self.Streams) self.Streams = append(self.Streams, stream) self.GotAudio = true @@ -275,8 +281,10 @@ func NewMuxer(w io.Writer) *Muxer { return self } +var SupportedCodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX} + func (self *Muxer) SupportedCodecTypes() []av.CodecType { - return []av.CodecType{av.H264, av.AAC, av.NELLYMOSER, av.SPEEX} + return SupportedCodecTypes } func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { diff --git a/format/flv/flvio/flvio.go b/format/flv/flvio/flvio.go index 3cebcd9..60249dd 100644 --- a/format/flv/flvio/flvio.go +++ b/format/flv/flvio/flvio.go @@ -5,6 +5,7 @@ import ( "time" "fmt" "github.com/nareix/pio" + "github.com/nareix/joy4/av" ) func TsToTime(ts int32) time.Duration { @@ -144,6 +145,14 @@ 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) Len() int { if self.SoundFormat == SOUND_AAC { return 2 + len(self.Data) diff --git a/format/rtmp/rtmp.go b/format/rtmp/rtmp.go index 05b5b8e..a9e1c5b 100644 --- a/format/rtmp/rtmp.go +++ b/format/rtmp/rtmp.go @@ -316,7 +316,7 @@ func createURL(tcurl, app, play string) (u *url.URL) { } func (self *Conn) SupportedCodecTypes() []av.CodecType { - return []av.CodecType{av.H264, av.AAC} + return flv.SupportedCodecTypes } func (self *Conn) recvConnect() (err error) {