diff --git a/av/av.go b/av/av.go index 950fe91..676f378 100644 --- a/av/av.go +++ b/av/av.go @@ -5,20 +5,21 @@ import ( "time" ) +// Audio sample format type SampleFormat uint8 const ( - U8 = SampleFormat(iota + 1) - S16 - S32 - FLT - DBL - U8P - S16P - S32P - FLTP - DBLP - U32 + U8 = SampleFormat(iota + 1) // 8-bit unsigned integer + S16 // signed 16-bit integer + S32 // signed 32-bit integer + FLT // 32-bit float + DBL // 64-bit float + U8P // 8-bit unsigned integer in planar + S16P // signed 16-bit integer in planar + S32P // signed 32-bit integer in planar + FLTP // 32-bit float in planar + DBLP // 64-bit float in planar + U32 // unsigned 32-bit integer ) func (self SampleFormat) BytesPerSample() int { @@ -63,6 +64,7 @@ func (self SampleFormat) String() string { } } +// checkout if this sample format is in planar func (self SampleFormat) IsPlanar() bool { switch self { case S16P, S32P, FLTP, DBLP: @@ -72,6 +74,7 @@ func (self SampleFormat) IsPlanar() bool { } } +// audio channel layout type ChannelLayout uint16 func (self ChannelLayout) String() string { @@ -107,8 +110,18 @@ func (self ChannelLayout) Count() (n int) { return } +// Video/Audio codec type. can be H264/AAC/SPEEX/... type CodecType uint32 +var ( + H264 = MakeVideoCodecType(avCodecTypeMagic + 1) + AAC = MakeAudioCodecType(avCodecTypeMagic + 1) + PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2) + PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3) + SPEEX = MakeAudioCodecType(avCodecTypeMagic + 4) + NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5) +) + const codecTypeAudioBit = 0x1 const codecTypeOtherBits = 1 @@ -130,19 +143,23 @@ func (self CodecType) String() string { return "" } +// CodecType is audio func (self CodecType) IsAudio() bool { return self&codecTypeAudioBit != 0 } +// CodecType is video func (self CodecType) IsVideo() bool { return self&codecTypeAudioBit == 0 } +// make a new audio codec type func MakeAudioCodecType(base uint32) (c CodecType) { c = CodecType(base)< 1 } +// audio frame duration func (self AudioFrame) Duration() time.Duration { return time.Second * time.Duration(self.SampleCount) / time.Duration(self.SampleRate) } +// check this audio frame has same format as other audio frame func (self AudioFrame) HasSameFormat(other AudioFrame) bool { if self.SampleRate != other.SampleRate { return false @@ -240,6 +273,7 @@ func (self AudioFrame) HasSameFormat(other AudioFrame) bool { return true } +// split sample audio sample from this frame func (self AudioFrame) Slice(start int, end int) (out AudioFrame) { out = self out.Data = append([][]byte(nil), out.Data...) @@ -251,6 +285,7 @@ func (self AudioFrame) Slice(start int, end int) (out AudioFrame) { return } +// concat two audio frames func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) { out = self out.Data = append([][]byte(nil), out.Data...) @@ -261,25 +296,31 @@ func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) { return } +// AudioEncoder can encode raw audio frame into compressed audio packets +// now cgo/ffmpeg inplements AudioEncoder, using ffmpeg.NewAudioEncoder to create it type AudioEncoder interface { - CodecData() (AudioCodecData, error) - Encode(AudioFrame) ([][]byte, error) + CodecData() (AudioCodecData, error) // encoder's codec data can put into container + Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s) //Flush() ([]Packet, error) - Close() - SetSampleRate(int) (error) - SetChannelLayout(ChannelLayout) (error) - SetSampleFormat(SampleFormat) (error) - SetBitrate(int) (error) - SetOption(string,interface{}) (error) - GetOption(string,interface{}) (error) + Close() // close encoder, free cgo contexts + SetSampleRate(int) (error) // set encoder sample rate + SetChannelLayout(ChannelLayout) (error) // set encoder channel layout + SetSampleFormat(SampleFormat) (error) // set encoder sample format + SetBitrate(int) (error) // set encoder bitrate + SetOption(string,interface{}) (error) // encoder setopt, in ffmpeg is av_opt_set_dict() + GetOption(string,interface{}) (error) // encoder getopt } +// AudioDecoder can decode compressed audio packets into raw audio frame +// use ffmpeg.NewAudioDecoder to create it type AudioDecoder interface { - Decode([]byte) (bool, AudioFrame, error) + Decode([]byte) (bool, AudioFrame, error) // decode one compressed audio packet //Flush() (AudioFrame, error) - Close() + Close() // close decode, free cgo contexts } +// AudioResampler can convert raw audio frames in different sample rate/format/channel layout type AudioResampler interface { - Resample(AudioFrame) (AudioFrame, error) + Resample(AudioFrame) (AudioFrame, error) // convert raw audio frames } + diff --git a/av/transcode/transcode.go b/av/transcode/transcode.go index 655c4f8..dfb3ae4 100644 --- a/av/transcode/transcode.go +++ b/av/transcode/transcode.go @@ -17,14 +17,17 @@ type tStream struct { adec av.AudioDecoder } +// Transcode options type Options struct { - FindAudioDecoderEncoder func(codec av.AudioCodecData, i int) (ok bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) + // if transcode is needed, create your AudioDecoder and AudioEncoder for Transcoder use. + FindAudioDecoderEncoder func(codec av.AudioCodecData, i int) (need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) } type Transcoder struct { streams []*tStream } +// Create new Transcoder func NewTranscoder(streams []av.CodecData, options Options) (_self *Transcoder, err error) { self := &Transcoder{} self.streams = []*tStream{} @@ -102,6 +105,10 @@ func (self *tStream) audioDecodeAndEncode(inpkt av.Packet) (outpkts []av.Packet, return } +// Do the transcode. +// +// in audio transcoding one Packet may transcode into many Packets. +// packet time will be adjusted in transcoder. func (self *Transcoder) Do(pkt av.Packet) (out []av.Packet, err error) { stream := self.streams[pkt.Idx] if stream.aenc != nil && stream.adec != nil { @@ -114,6 +121,7 @@ func (self *Transcoder) Do(pkt av.Packet) (out []av.Packet, err error) { return } +// CodecData after transcode func (self *Transcoder) Streams() (streams []av.CodecData, err error) { for _, stream := range self.streams { streams = append(streams, stream.codec) @@ -121,6 +129,7 @@ func (self *Transcoder) Streams() (streams []av.CodecData, err error) { return } +// Close transcoder, will close related encoder and decoders func (self *Transcoder) Close() (err error) { for _, stream := range self.streams { if stream.aenc != nil { @@ -136,10 +145,12 @@ func (self *Transcoder) Close() (err error) { return } +// Wrap transcoder and origin Muxer into new Muxer. +// write to new Muxer will do transcode automatically type Muxer struct { - av.Muxer + av.Muxer // origin Muxer transcoder *Transcoder - Options + Options // transcode options } func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { @@ -176,6 +187,8 @@ func (self *Muxer) Close() (err error) { return } +// Wrap transcoder and origin Demuxer into new Demuxer. +// read this Demuxer will do transcode automatically type Demuxer struct { av.Demuxer transcoder *Transcoder