add SampleFormat ChannelLayout
This commit is contained in:
parent
33495dece0
commit
0c75342d60
195
av.go
195
av.go
@ -31,6 +31,33 @@ func (self SampleFormat) BytesPerSample() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self SampleFormat) String() string {
|
||||||
|
switch self {
|
||||||
|
case U8:
|
||||||
|
return "U8"
|
||||||
|
case S16:
|
||||||
|
return "S16"
|
||||||
|
case S32:
|
||||||
|
return "S32"
|
||||||
|
case FLT:
|
||||||
|
return "FLT"
|
||||||
|
case DBL:
|
||||||
|
return "DBL"
|
||||||
|
case U8P:
|
||||||
|
return "U8P"
|
||||||
|
case S16P:
|
||||||
|
return "S16P"
|
||||||
|
case FLTP:
|
||||||
|
return "FLTP"
|
||||||
|
case DBLP:
|
||||||
|
return "DBLP"
|
||||||
|
case U32:
|
||||||
|
return "U32"
|
||||||
|
default:
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (self SampleFormat) IsPlanar() bool {
|
func (self SampleFormat) IsPlanar() bool {
|
||||||
switch self {
|
switch self {
|
||||||
case S16P,S32P,FLTP,DBLP:
|
case S16P,S32P,FLTP,DBLP:
|
||||||
@ -40,11 +67,83 @@ func (self SampleFormat) IsPlanar() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChannelLayout uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
H264 = 0x264
|
CH_FRONT_CENTER = ChannelLayout(1<<iota)
|
||||||
AAC = 0xaac
|
CH_FRONT_LEFT
|
||||||
|
CH_FRONT_RIGHT
|
||||||
|
CH_BACK_CENTER
|
||||||
|
CH_BACK_LEFT
|
||||||
|
CH_BACK_RIGHT
|
||||||
|
CH_SIDE_LEFT
|
||||||
|
CH_SIDE_RIGHT
|
||||||
|
CH_LOW_FREQ
|
||||||
|
CH_NR
|
||||||
|
|
||||||
|
CH_MONO = ChannelLayout(CH_FRONT_CENTER)
|
||||||
|
CH_STEREO = ChannelLayout(CH_FRONT_LEFT|CH_FRONT_RIGHT)
|
||||||
|
CH_2_1 = ChannelLayout(CH_STEREO|CH_BACK_CENTER)
|
||||||
|
CH_2POINT1 = ChannelLayout(CH_STEREO|CH_LOW_FREQ)
|
||||||
|
CH_SURROUND = ChannelLayout(CH_STEREO|CH_FRONT_CENTER)
|
||||||
|
CH_3POINT1 = ChannelLayout(CH_SURROUND|CH_LOW_FREQ)
|
||||||
|
// TODO: add all channel_layout in ffmpeg
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (self ChannelLayout) Count() (n int) {
|
||||||
|
for self != 0 {
|
||||||
|
n++
|
||||||
|
self = (self-1)&self
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
H264 = iota+0x264
|
||||||
|
AAC
|
||||||
|
PCM_MULAW
|
||||||
|
)
|
||||||
|
|
||||||
|
type BasicAudioCodecData struct {
|
||||||
|
CodecType int
|
||||||
|
CodecSampleRate int
|
||||||
|
CodecChannelLayout ChannelLayout
|
||||||
|
CodecSampleFormat SampleFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) Type() int {
|
||||||
|
return self.CodecType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) IsAudio() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) IsVideo() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) SampleRate() int {
|
||||||
|
return self.CodecSampleRate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) ChannelLayout() ChannelLayout {
|
||||||
|
return self.CodecChannelLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self BasicAudioCodecData) SampleFormat() SampleFormat {
|
||||||
|
return self.CodecSampleFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPCMMulawCodecData() AudioCodecData {
|
||||||
|
return BasicAudioCodecData{
|
||||||
|
CodecType: PCM_MULAW,
|
||||||
|
CodecSampleFormat: S16,
|
||||||
|
CodecChannelLayout: CH_MONO,
|
||||||
|
CodecSampleRate: 8000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type CodecData interface {
|
type CodecData interface {
|
||||||
IsVideo() bool
|
IsVideo() bool
|
||||||
IsAudio() bool
|
IsAudio() bool
|
||||||
@ -61,7 +160,7 @@ type AudioCodecData interface {
|
|||||||
CodecData
|
CodecData
|
||||||
SampleFormat() SampleFormat
|
SampleFormat() SampleFormat
|
||||||
SampleRate() int
|
SampleRate() int
|
||||||
ChannelCount() int
|
ChannelLayout() ChannelLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
type H264CodecData interface {
|
type H264CodecData interface {
|
||||||
@ -97,67 +196,57 @@ type Packet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AudioFrame struct {
|
type AudioFrame struct {
|
||||||
|
SampleRate int
|
||||||
SampleFormat SampleFormat
|
SampleFormat SampleFormat
|
||||||
ChannelCount int
|
ChannelLayout ChannelLayout
|
||||||
Bytes []byte
|
SampleCount int
|
||||||
|
Data [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self AudioFrame) HasSameFormat(other AudioFrame) bool {
|
||||||
|
if self.SampleRate != other.SampleRate {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if self.ChannelLayout != other.ChannelLayout {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if self.SampleFormat != other.SampleFormat {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self AudioFrame) Slice(start int, end int) (out AudioFrame) {
|
||||||
|
out = self
|
||||||
|
out.SampleCount = end-start
|
||||||
|
size := self.SampleFormat.BytesPerSample()
|
||||||
|
for i := range out.Data {
|
||||||
|
out.Data[i] = out.Data[i][start*size:end*size]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) {
|
||||||
|
out = self
|
||||||
|
out.SampleCount += in.SampleCount
|
||||||
|
for i := range out.Data {
|
||||||
|
out.Data[i] = append(out.Data[i], in.Data[i]...)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type AudioEncoder interface {
|
type AudioEncoder interface {
|
||||||
CodecData() AudioCodecData
|
CodecData() AudioCodecData
|
||||||
Encode(AudioFrame) ([]Packet, error)
|
Encode(AudioFrame) ([]Packet, error)
|
||||||
Flush() ([]Packet, error)
|
//Flush() ([]Packet, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AudioDecoder interface {
|
type AudioDecoder interface {
|
||||||
Decode(Packet) (AudioFrame, error)
|
Decode(Packet) (AudioFrame, error)
|
||||||
Flush() (AudioFrame, error)
|
//Flush() (AudioFrame, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
type AudioResampler interface {
|
||||||
在写入数据包的时候必须严格按照 V-A-A-A-V-A-A-A-.... 顺序,所有包的时间都必须正确
|
Resample(AudioFrame) (AudioFrame, error)
|
||||||
如果有误,跳过错的那一段
|
|
||||||
|
|
||||||
cli := rtsp.Open("xxoo")
|
|
||||||
cli = &av.TranscodeDemuxer{
|
|
||||||
Demuxer: cli,
|
|
||||||
Transcoders: []Transcoder{ffmpeg.AudioTranscodeTo("aac")},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<script class="miniplayer" controls=true autoplay=true minidash-src="stream1" src="//site/minidash.min.js"></script>
|
|
||||||
|
|
||||||
minidash.open('src', function(video) {
|
|
||||||
})
|
|
||||||
|
|
||||||
minidash.HandleConn(func(conn *minidash.Conn) {
|
|
||||||
conn.RequestSrc
|
|
||||||
muxer, err := conn.WriteHeader(cli.Streams())
|
|
||||||
muxer.WritePacket()
|
|
||||||
})
|
|
||||||
|
|
||||||
怎样转码
|
|
||||||
av.Transconder{
|
|
||||||
TranscodeHeader(codecData) ok, codecData, error
|
|
||||||
TranscodePacket(Packet, flush) []Packet, error
|
|
||||||
FlushPacket() []Packet, error
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder := ffmpeg.FindAudioDecoder(AudioCodecData)
|
|
||||||
decoder := ffmpeg.FindAudioDecoderByName("aac", CodecData)
|
|
||||||
|
|
||||||
av.DemuxTranscoder{
|
|
||||||
Demuxer Demuxer
|
|
||||||
Transconders []Transconder
|
|
||||||
}
|
|
||||||
Streams()
|
|
||||||
ReadPacket()
|
|
||||||
ClearPacketCache()
|
|
||||||
|
|
||||||
怎样混合多个Demuxer
|
|
||||||
DemuxerMixer{
|
|
||||||
demuxer
|
|
||||||
}
|
|
||||||
demuxer.FilterStreams()
|
|
||||||
streams := demuxer.Streams()
|
|
||||||
streams[0]
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@ -10,16 +10,19 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hashParams(params []interface{}) uint64 {
|
func hashParams(params []interface{}) (res uint64, err error) {
|
||||||
f := fnv.New64()
|
f := fnv.New64()
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
if s, ok := p.(string); ok {
|
if s, ok := p.(string); ok {
|
||||||
io.WriteString(f, s)
|
io.WriteString(f, s)
|
||||||
} else {
|
} else {
|
||||||
binary.Write(f, binary.LittleEndian, p)
|
if err = binary.Write(f, binary.LittleEndian, p); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f.Sum64()
|
}
|
||||||
|
res = f.Sum64()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Publisher struct {
|
type Publisher struct {
|
||||||
@ -166,7 +169,11 @@ func (self *Proxy) HandleSubscribe(fn func(*Publisher)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Proxy) Publish(params ...interface{}) (pub *Publisher, err error) {
|
func (self *Proxy) Publish(params ...interface{}) (pub *Publisher, err error) {
|
||||||
h := hashParams(params)
|
var h uint64
|
||||||
|
if h, err = hashParams(params); err != nil {
|
||||||
|
err = fmt.Errorf("please use string/int in Publish() params")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
pub, exists := self.publishers[h]
|
pub, exists := self.publishers[h]
|
||||||
@ -188,7 +195,11 @@ func (self *Proxy) Publish(params ...interface{}) (pub *Publisher, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Proxy) Subscribe(params ...interface{}) (sub *Subscriber, err error) {
|
func (self *Proxy) Subscribe(params ...interface{}) (sub *Subscriber, err error) {
|
||||||
h := hashParams(params)
|
var h uint64
|
||||||
|
if h, err = hashParams(params); err != nil {
|
||||||
|
err = fmt.Errorf("please use string/int in Subscribe() params")
|
||||||
|
return
|
||||||
|
}
|
||||||
needcb := false
|
needcb := false
|
||||||
|
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user