diff --git a/av/av.go b/av/av.go index 76b1f615..91503355 100644 --- a/av/av.go +++ b/av/av.go @@ -1,27 +1,28 @@ - // Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode. package av import ( "fmt" "time" + + "github.com/jinleileiking/joy4/common" ) // Audio sample format. type SampleFormat uint8 const ( - 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 + 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 { @@ -116,11 +117,11 @@ func (self ChannelLayout) Count() (n int) { 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) + 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) ) @@ -171,7 +172,7 @@ const avCodecTypeMagic = 233333 // can be converted to VideoCodecData or AudioCodecData using: // // codecdata.(AudioCodecData) or codecdata.(VideoCodecData) -// +// // for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS. type CodecData interface { Type() CodecType // Video/Audio codec type @@ -179,15 +180,15 @@ type CodecData interface { type VideoCodecData interface { CodecData - Width() int // Video height + Width() int // Video height Height() int // Video width } type AudioCodecData interface { CodecData - SampleFormat() SampleFormat // audio sample format - SampleRate() int // audio sample rate - ChannelLayout() ChannelLayout // audio channel layout + SampleFormat() SampleFormat // audio sample format + SampleRate() int // audio sample rate + ChannelLayout() ChannelLayout // audio channel layout PacketDuration([]byte) (time.Duration, error) // get audio compressed packet duration } @@ -196,16 +197,16 @@ type PacketWriter interface { } type PacketReader interface { - ReadPacket() (Packet,error) + ReadPacket() (Packet, error) } // Muxer describes the steps of writing compressed audio/video packets into container formats like MP4/FLV/MPEG-TS. -// +// // Container formats, rtmp.Conn, and transcode.Muxer implements Muxer interface. type Muxer interface { WriteHeader([]CodecData) error // write the file header - PacketWriter // write compressed audio/video packets - WriteTrailer() error // finish writing file, this func can be called only once + PacketWriter // write compressed audio/video packets + WriteTrailer() error // finish writing file, this func can be called only once } // Muxer with Close() method @@ -216,7 +217,7 @@ type MuxCloser interface { // Demuxer can read compressed audio/video packets from container formats like MP4/FLV/MPEG-TS. type Demuxer interface { - PacketReader // read compressed audio/video packets + PacketReader // read compressed audio/video packets Streams() ([]CodecData, error) // reads the file header, contains video/audio meta infomations } @@ -228,20 +229,25 @@ type DemuxCloser interface { // Packet stores compressed audio/video data. type Packet struct { - IsKeyFrame bool // video packet is key frame - Idx int8 // stream index in container format + IsKeyFrame bool // video packet is key frame + Idx int8 // stream index in container format CompositionTime time.Duration // packet presentation time minus decode time for H264 B-Frame + Timestamp int32 + AVCPacketType string + NALUFormat string + NALUInfos []common.TNALUInfo + Time time.Duration // packet decode time - Data []byte // packet data + Data []byte // packet data } // Raw audio frame. type AudioFrame struct { - SampleFormat SampleFormat // audio sample format, e.g: S16,FLTP,... + SampleFormat SampleFormat // audio sample format, e.g: S16,FLTP,... ChannelLayout ChannelLayout // audio channel layout, e.g: CH_MONO,CH_STEREO,... - SampleCount int // sample count in this frame - SampleRate int // sample rate - Data [][]byte // data array for planar format len(Data) > 1 + SampleCount int // sample count in this frame + SampleRate int // sample rate + Data [][]byte // data array for planar format len(Data) > 1 } func (self AudioFrame) Duration() time.Duration { @@ -291,26 +297,25 @@ func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) { // AudioEncoder can encode raw audio frame into compressed audio packets. // cgo/ffmpeg inplements AudioEncoder, using ffmpeg.NewAudioEncoder to create it. type AudioEncoder interface { - CodecData() (AudioCodecData, error) // encoder's codec data can put into container - Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s) - 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 + CodecData() (AudioCodecData, error) // encoder's codec data can put into container + Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s) + 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 one compressed audio packet - Close() // close decode, free cgo contexts + 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) // convert raw audio frames } - diff --git a/av/avconv/avconv.go b/av/avconv/avconv.go index fa8a5a76..f523f367 100644 --- a/av/avconv/avconv.go +++ b/av/avconv/avconv.go @@ -4,10 +4,10 @@ import ( "fmt" "io" "time" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/pktque" - "github.com/nareix/joy4/av/transcode" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/pktque" + "github.com/jinleileiking/joy4/av/transcode" ) var Debug bool diff --git a/av/avutil/avutil.go b/av/avutil/avutil.go index 59ebd4a0..3437ee6d 100644 --- a/av/avutil/avutil.go +++ b/av/avutil/avutil.go @@ -5,7 +5,7 @@ import ( "strings" "fmt" "bytes" - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/av" "net/url" "os" "path" diff --git a/av/pktque/buf.go b/av/pktque/buf.go index 6624f559..fcb9ac6d 100644 --- a/av/pktque/buf.go +++ b/av/pktque/buf.go @@ -1,7 +1,7 @@ package pktque import ( - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/av" ) type Buf struct { diff --git a/av/pktque/filters.go b/av/pktque/filters.go index 83b943d2..2e90fa70 100644 --- a/av/pktque/filters.go +++ b/av/pktque/filters.go @@ -4,7 +4,7 @@ package pktque import ( "time" - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/av" ) type Filter interface { diff --git a/av/pubsub/queue.go b/av/pubsub/queue.go index 10b3f735..a1a89307 100644 --- a/av/pubsub/queue.go +++ b/av/pubsub/queue.go @@ -2,8 +2,8 @@ package pubsub import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/pktque" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/pktque" "io" "sync" "time" diff --git a/av/transcode/transcode.go b/av/transcode/transcode.go index 6f512d97..ff514e24 100644 --- a/av/transcode/transcode.go +++ b/av/transcode/transcode.go @@ -5,8 +5,8 @@ package transcode import ( "fmt" "time" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/pktque" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/pktque" ) var Debug bool diff --git a/cgo/ffmpeg/audio.go b/cgo/ffmpeg/audio.go index fbd676dc..2f8b1bac 100644 --- a/cgo/ffmpeg/audio.go +++ b/cgo/ffmpeg/audio.go @@ -16,9 +16,9 @@ import ( "runtime" "fmt" "time" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/codec/aacparser" ) const debug = false diff --git a/cgo/ffmpeg/video.go b/cgo/ffmpeg/video.go index 085b229a..5059e1b3 100644 --- a/cgo/ffmpeg/video.go +++ b/cgo/ffmpeg/video.go @@ -14,8 +14,8 @@ import ( "fmt" "image" "reflect" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/h264parser" ) type VideoDecoder struct { diff --git a/codec/aacparser/parser.go b/codec/aacparser/parser.go index 6432574a..f555b567 100644 --- a/codec/aacparser/parser.go +++ b/codec/aacparser/parser.go @@ -1,8 +1,8 @@ package aacparser import ( - "github.com/nareix/joy4/utils/bits" - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/utils/bits" + "github.com/jinleileiking/joy4/av" "time" "fmt" "bytes" diff --git a/codec/codec.go b/codec/codec.go index d37df77c..ac13f4f5 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -1,8 +1,8 @@ package codec import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/fake" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/fake" "time" ) diff --git a/codec/fake/fake.go b/codec/fake/fake.go index 51e056f4..82568d6f 100644 --- a/codec/fake/fake.go +++ b/codec/fake/fake.go @@ -1,7 +1,7 @@ package fake import ( - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/av" ) type CodecData struct { diff --git a/codec/h264parser/parser.go b/codec/h264parser/parser.go index 35c8d837..8a391ca7 100644 --- a/codec/h264parser/parser.go +++ b/codec/h264parser/parser.go @@ -1,12 +1,13 @@ - package h264parser import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/utils/bits" - "github.com/nareix/joy4/utils/bits/pio" - "fmt" "bytes" + "fmt" + + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/common" + "github.com/jinleileiking/joy4/utils/bits" + "github.com/jinleileiking/joy4/utils/bits/pio" ) const ( @@ -131,7 +132,7 @@ Annex B is commonly used in live and streaming formats such as transport streams 2. AVCC The other common method of storing an H.264 stream is the AVCC format. In this format, each NALU is preceded with its length (in big endian format). This method is easier to parse, but you lose the byte alignment features of Annex B. Just to complicate things, the length may be encoded using 1, 2 or 4 bytes. This value is stored in a header object. This header is often called ‘extradata’ or ‘sequence header’. Its basic format is as follows: -bits +bits 8 version ( always 0x01 ) 8 avc profile ( sps[0][1] ) 8 avc compatibility ( sps[0][2] ) @@ -199,8 +200,8 @@ Additionally, there is a new variable called NALULengthSizeMinusOne. This confus An advantage to this format is the ability to configure the decoder at the start and jump into the middle of a stream. This is a common use case where the media is available on a random access medium such as a hard drive, and is therefore used in common container formats such as MP4 and MKV. */ -var StartCodeBytes = []byte{0,0,1} -var AUDBytes = []byte{0,0,0,1,0x9,0xf0,0,0,0,1} // AUD +var StartCodeBytes = []byte{0, 0, 1} +var AUDBytes = []byte{0, 0, 0, 1, 0x9, 0xf0, 0, 0, 0, 1} // AUD func CheckNALUsType(b []byte) (typ int) { _, typ = SplitNALUs(b) @@ -499,9 +500,9 @@ func ParseSPS(data []byte) (self SPSInfo, err error) { } type CodecData struct { - Record []byte + Record []byte RecordInfo AVCDecoderConfRecord - SPSInfo SPSInfo + SPSInfo SPSInfo } func (self CodecData) Type() av.CodecType { @@ -589,8 +590,8 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { self.AVCProfileIndication = b[1] self.ProfileCompatibility = b[2] self.AVCLevelIndication = b[3] - self.LengthSizeMinusOne = b[4]&0x03 - spscount := int(b[5]&0x1f) + self.LengthSizeMinusOne = b[4] & 0x03 + spscount := int(b[5] & 0x1f) n += 6 for i := 0; i < spscount; i++ { @@ -638,10 +639,10 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { func (self AVCDecoderConfRecord) Len() (n int) { n = 7 for _, sps := range self.SPS { - n += 2+len(sps) + n += 2 + len(sps) } for _, pps := range self.PPS { - n += 2+len(pps) + n += 2 + len(pps) } return } @@ -651,8 +652,8 @@ func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) { b[1] = self.AVCProfileIndication b[2] = self.ProfileCompatibility b[3] = self.AVCLevelIndication - b[4] = self.LengthSizeMinusOne|0xfc - b[5] = uint8(len(self.SPS))|0xe0 + b[4] = self.LengthSizeMinusOne | 0xfc + b[5] = uint8(len(self.SPS)) | 0xe0 n += 6 for _, sps := range self.SPS { @@ -690,28 +691,41 @@ func (self SliceType) String() string { } const ( - SLICE_P = iota+1 + SLICE_P = iota + 1 SLICE_B SLICE_I ) -func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { +func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, info common.TNALUInfo, err error) { + + // spew.Printf("%08b\n", packet[0]&0x1f) + info.RefIdc = (int(packet[0]&0x1f) >> 5) + + info.UnitType = MAP_UNIT_TYPE[int(packet[0]&0x1f)] + info.NumBytes = len(packet) + info.Data = append(info.Data, packet...) + + // if info.UnitType == "FILLER" { + // if len(packet) > 16 { + // spew.Dump(packet[0:15]) + // } + // } if len(packet) <= 1 { err = fmt.Errorf("h264parser: packet too short to parse slice header") return } - nal_unit_type := packet[0]&0x1f - switch nal_unit_type { - case 1,2,5,19: - // slice_layer_without_partitioning_rbsp - // slice_data_partition_a_layer_rbsp + // nal_unit_type := packet[0] & 0x1f + // switch nal_unit_type { + // case 1, 2, 5, 19: + // // slice_layer_without_partitioning_rbsp + // // slice_data_partition_a_layer_rbsp - default: - err = fmt.Errorf("h264parser: nal_unit_type=%d has no slice header", nal_unit_type) - return - } + // default: + // err = fmt.Errorf("h264parser: nal_unit_type=%d has no slice header", nal_unit_type) + // return + // } r := &bits.GolombBitReader{R: bytes.NewReader(packet[1:])} @@ -727,17 +741,80 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { } switch u { - case 0,3,5,8: + case 0, 3, 5, 8: sliceType = SLICE_P - case 1,6: + case 1, 6: sliceType = SLICE_B - case 2,4,7,9: + case 2, 4, 7, 9: sliceType = SLICE_I - default: - err = fmt.Errorf("h264parser: slice_type=%d invalid", u) - return + // default: + // err = fmt.Errorf("h264parser: slice_type=%d invalid", u) + // return } + info.SliceType = MAP_SLICE_TYPE[int(u)] return } +func ParseNALUs(b []byte) (info common.TNALUInfos) { + nalus, nal_type := SplitNALUs(b) + + if nal_type == NALU_AVCC { + info.NALUFormat = "AVCC" + } else if nal_type == NALU_RAW { + info.NALUFormat = "RAW" + } else if nal_type == NALU_ANNEXB { + info.NALUFormat = "ANNEXB" + } else { + info.NALUFormat = "OTHER" + } + + for _, nalu := range nalus { + if _, inf, err := ParseSliceHeaderFromNALU(nalu); err == nil { + info.Infos = append(info.Infos, inf) + } else { + fmt.Println("Error parse header") + } + + } + return +} + +var MAP_UNIT_TYPE map[int]string +var MAP_SLICE_TYPE map[int]string + +func init() { + MAP_UNIT_TYPE = map[int]string{ + 0: "(0)ERROR", + 1: "(1)N-IDR", + 2: "(2)SliceA", + 3: "(3)SliceB", + 4: "(4)SliceC", + 5: "(5)IDR", + 6: "(6)SEI", + 7: "(7)SPS", + 8: "(8)PPS", + 9: "(9)AUD", + 10: "(10)EOSEQ", + 11: "(11)EOSTREAM", + 12: "(12)FILLER", + 13: "(13)SPS-EXT", + 14: "REV 14", + 15: "REV 15", + 16: "REV 16", + 17: "REV 17", + 18: "REV 18", + } + MAP_SLICE_TYPE = map[int]string{ + 0: "P", + 1: "B", + 2: "I", + 3: "SP", + 4: "SI", + 5: "P", + 6: "B", + 7: "I", + 8: "SP", + 9: "SI", + } +} diff --git a/common/common.go b/common/common.go new file mode 100644 index 00000000..f5beb51d --- /dev/null +++ b/common/common.go @@ -0,0 +1,14 @@ +package common + +type TNALUInfos struct { + NALUFormat string + Infos []TNALUInfo +} + +type TNALUInfo struct { + UnitType string + RefIdc int + NumBytes int + Data []byte + SliceType string +} diff --git a/examples/audio_decode/main.go b/examples/audio_decode/main.go index 99594bed..260f97a0 100644 --- a/examples/audio_decode/main.go +++ b/examples/audio_decode/main.go @@ -2,10 +2,10 @@ package main import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/cgo/ffmpeg" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/cgo/ffmpeg" ) // need ffmpeg installed diff --git a/examples/http_flv_and_rtmp_server/main.go b/examples/http_flv_and_rtmp_server/main.go index 28916973..27d02ca4 100644 --- a/examples/http_flv_and_rtmp_server/main.go +++ b/examples/http_flv_and_rtmp_server/main.go @@ -4,11 +4,11 @@ import ( "sync" "io" "net/http" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/av/pubsub" - "github.com/nareix/joy4/format/rtmp" - "github.com/nareix/joy4/format/flv" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/av/pubsub" + "github.com/jinleileiking/joy4/format/rtmp" + "github.com/jinleileiking/joy4/format/flv" ) func init() { diff --git a/examples/open_probe_file/main.go b/examples/open_probe_file/main.go index 4960fdd9..db0eac14 100644 --- a/examples/open_probe_file/main.go +++ b/examples/open_probe_file/main.go @@ -2,9 +2,9 @@ package main import ( "fmt" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/format" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/format" ) func init() { diff --git a/examples/rtmp_publish/main.go b/examples/rtmp_publish/main.go index 4c39af8b..4fc4a1be 100644 --- a/examples/rtmp_publish/main.go +++ b/examples/rtmp_publish/main.go @@ -1,10 +1,10 @@ package main import ( - "github.com/nareix/joy4/av/pktque" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/format/rtmp" + "github.com/jinleileiking/joy4/av/pktque" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/format/rtmp" ) func init() { diff --git a/examples/rtmp_server_channels/main.go b/examples/rtmp_server_channels/main.go index 36170c0d..50d47f95 100644 --- a/examples/rtmp_server_channels/main.go +++ b/examples/rtmp_server_channels/main.go @@ -2,12 +2,12 @@ package main import ( "fmt" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/av/pktque" - "github.com/nareix/joy4/av/pubsub" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/format/rtmp" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/av/pktque" + "github.com/jinleileiking/joy4/av/pubsub" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/format/rtmp" "sync" "time" ) diff --git a/examples/rtmp_server_proxy/main.go b/examples/rtmp_server_proxy/main.go index 43fd20d8..d171f1f5 100644 --- a/examples/rtmp_server_proxy/main.go +++ b/examples/rtmp_server_proxy/main.go @@ -3,9 +3,9 @@ package main import ( "fmt" "strings" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/format/rtmp" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/format/rtmp" ) func init() { diff --git a/examples/rtmp_server_speex_to_aac/main.go b/examples/rtmp_server_speex_to_aac/main.go index 3f00b371..aecb5222 100644 --- a/examples/rtmp_server_speex_to_aac/main.go +++ b/examples/rtmp_server_speex_to_aac/main.go @@ -1,12 +1,12 @@ package main import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/transcode" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/format/rtmp" - "github.com/nareix/joy4/cgo/ffmpeg" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/transcode" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/format/rtmp" + "github.com/jinleileiking/joy4/cgo/ffmpeg" ) // need ffmpeg with libspeex and libfdkaac installed diff --git a/examples/transcode/main.go b/examples/transcode/main.go index 29101193..42ce3a15 100644 --- a/examples/transcode/main.go +++ b/examples/transcode/main.go @@ -1,11 +1,11 @@ package main import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/transcode" - "github.com/nareix/joy4/format" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/cgo/ffmpeg" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/transcode" + "github.com/jinleileiking/joy4/format" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/cgo/ffmpeg" ) // need ffmpeg with libfdkaac installed diff --git a/format/aac/aac.go b/format/aac/aac.go index 5a65a874..fbe74810 100644 --- a/format/aac/aac.go +++ b/format/aac/aac.go @@ -2,9 +2,9 @@ package aac import ( - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/aacparser" "time" "fmt" "io" diff --git a/format/flv/flv.go b/format/flv/flv.go index 6f07da64..1746bad4 100644 --- a/format/flv/flv.go +++ b/format/flv/flv.go @@ -3,15 +3,16 @@ package flv import ( "bufio" "fmt" - "github.com/nareix/joy4/utils/bits/pio" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/codec" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/fake" - "github.com/nareix/joy4/codec/h264parser" - "github.com/nareix/joy4/format/flv/flvio" "io" + + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/codec" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/fake" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/flv/flvio" + "github.com/jinleileiking/joy4/utils/bits/pio" ) var MaxProbePacketCount = 20 @@ -91,9 +92,12 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) { err = fmt.Errorf("flv: h264 seqhdr invalid") return } + + // spew.Dump(stream) self.VideoStreamIdx = len(self.Streams) self.Streams = append(self.Streams, stream) self.GotVideo = true + self.CacheTag(tag, timestamp) } case flvio.AVC_NALU: @@ -171,7 +175,20 @@ func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, ok = true pkt.Data = tag.Data pkt.CompositionTime = flvio.TsToTime(tag.CompositionTime) + pkt.Timestamp = tag.Timestamp + pkt.AVCPacketType = "NALU" + pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY + pkt.NALUFormat = tag.NALUFormat + pkt.NALUInfos = tag.NALUInfos + case flvio.AVC_SEQHDR: + pkt.AVCPacketType = "SEQHDR" pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY + pkt.Data = tag.Data + case flvio.AVC_EOS: + ok = true + pkt.AVCPacketType = "EOS" + pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY + pkt.Data = tag.Data } case flvio.TAG_AUDIO: diff --git a/format/flv/flvio/amf0.go b/format/flv/flvio/amf0.go index 05b4a037..d9feef87 100644 --- a/format/flv/flvio/amf0.go +++ b/format/flv/flvio/amf0.go @@ -5,7 +5,7 @@ import ( "math" "fmt" "time" - "github.com/nareix/joy4/utils/bits/pio" + "github.com/jinleileiking/joy4/utils/bits/pio" ) type AMF0ParseError struct { diff --git a/format/flv/flvio/flvio.go b/format/flv/flvio/flvio.go index aca07708..8cb1bcf5 100644 --- a/format/flv/flvio/flvio.go +++ b/format/flv/flvio/flvio.go @@ -2,10 +2,14 @@ package flvio import ( "fmt" - "github.com/nareix/joy4/utils/bits/pio" - "github.com/nareix/joy4/av" "io" "time" + + "github.com/davecgh/go-spew/spew" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/common" + "github.com/jinleileiking/joy4/utils/bits/pio" ) func TsToTime(ts int32) time.Duration { @@ -149,7 +153,11 @@ type Tag struct { CompositionTime int32 - Data []byte + Data []byte + Timestamp int32 + + NALUFormat string + NALUInfos []common.TNALUInfo } func (self Tag) ChannelLayout() av.ChannelLayout { @@ -204,6 +212,7 @@ func (self Tag) audioFillHeader(b []byte) (n int) { return } +// VIDEODATA + AVCVIDEOPACKET func (self *Tag) videoParseHeader(b []byte) (n int, err error) { if len(b) < n+1 { err = fmt.Errorf("videodata: parse invalid") @@ -276,6 +285,8 @@ const ( const TagHeaderLength = 11 const TagTrailerLength = 4 +//FLVTAG +// 09/08 ... xxxxx func ParseTagHeader(b []byte) (tag Tag, ts int32, datalen int, err error) { tagtype := b[0] @@ -308,20 +319,62 @@ func ReadTag(r io.Reader, b []byte) (tag Tag, ts int32, err error) { return } - data := make([]byte, datalen) - if _, err = io.ReadFull(r, data); err != nil { - return - } + if datalen != 0 { + data := make([]byte, datalen) + if _, err = io.ReadFull(r, data); err != nil { + return + } + + var n int + if n, err = (&tag).ParseHeader(data); err != nil { + return + } + tag.Data = data[n:] + tag.Timestamp = ts + + // Data is h264 nalus + if tag.Type == TAG_VIDEO && len(tag.Data) != 0 { + + nalus, nal_type := h264parser.SplitNALUs(tag.Data) + + if nal_type == h264parser.NALU_AVCC { + tag.NALUFormat = "AVCC" + } + + if nal_type == h264parser.NALU_RAW { + tag.NALUFormat = "RAW" + } + + if nal_type == h264parser.NALU_ANNEXB { + tag.NALUFormat = "ANNEXB" + } + + for _, nalu := range nalus { + // spew.Dump(nalus) + // os.Exit(1) + if _, info, err := h264parser.ParseSliceHeaderFromNALU(nalu); err == nil { + // spew.Dump(info) + tag.NALUInfos = append(tag.NALUInfos, info) + } else { + spew.Dump(err) + } + + } + + // spew.Dump(tag.NALUInfos) + } + + if tag.Type == TAG_VIDEO && len(tag.Data) == 0 { + tag.NALUFormat = "N/A" + } - var n int - if n, err = (&tag).ParseHeader(data); err != nil { - return } - tag.Data = data[n:] + // b[:4] ---> preTagSize if _, err = io.ReadFull(r, b[:4]); err != nil { return } + return } diff --git a/format/format.go b/format/format.go index 1c07ac8f..f490c717 100644 --- a/format/format.go +++ b/format/format.go @@ -1,13 +1,13 @@ package format import ( - "github.com/nareix/joy4/format/mp4" - "github.com/nareix/joy4/format/ts" - "github.com/nareix/joy4/format/rtmp" - "github.com/nareix/joy4/format/rtsp" - "github.com/nareix/joy4/format/flv" - "github.com/nareix/joy4/format/aac" - "github.com/nareix/joy4/av/avutil" + "github.com/jinleileiking/joy4/format/mp4" + "github.com/jinleileiking/joy4/format/ts" + "github.com/jinleileiking/joy4/format/rtmp" + "github.com/jinleileiking/joy4/format/rtsp" + "github.com/jinleileiking/joy4/format/flv" + "github.com/jinleileiking/joy4/format/aac" + "github.com/jinleileiking/joy4/av/avutil" ) func RegisterAll() { diff --git a/format/mp4/demuxer.go b/format/mp4/demuxer.go index dbd91376..c8868096 100644 --- a/format/mp4/demuxer.go +++ b/format/mp4/demuxer.go @@ -3,10 +3,10 @@ package mp4 import ( "time" "fmt" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/h264parser" - "github.com/nareix/joy4/format/mp4/mp4io" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/mp4/mp4io" "io" ) diff --git a/format/mp4/handler.go b/format/mp4/handler.go index aeef1cc3..a3b4cbe7 100644 --- a/format/mp4/handler.go +++ b/format/mp4/handler.go @@ -2,8 +2,8 @@ package mp4 import ( "io" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" ) var CodecTypes = []av.CodecType{av.H264, av.AAC} diff --git a/format/mp4/mp4io/atoms.go b/format/mp4/mp4io/atoms.go index c90485cc..f5163a12 100644 --- a/format/mp4/mp4io/atoms.go +++ b/format/mp4/mp4io/atoms.go @@ -1,6 +1,6 @@ package mp4io -import "github.com/nareix/joy4/utils/bits/pio" +import "github.com/jinleileiking/joy4/utils/bits/pio" import "time" const MOOF = Tag(0x6d6f6f66) diff --git a/format/mp4/mp4io/gen/gen.go b/format/mp4/mp4io/gen/gen.go index 1a2857f3..8b9ade84 100644 --- a/format/mp4/mp4io/gen/gen.go +++ b/format/mp4/mp4io/gen/gen.go @@ -967,7 +967,7 @@ func genatoms(filename, outfilename string) { &ast.GenDecl{ Tok: token.IMPORT, Specs: []ast.Spec{ - &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/nareix/joy4/utils/bits/pio"`}}, + &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/jinleileiking/joy4/utils/bits/pio"`}}, }, }, &ast.GenDecl{ diff --git a/format/mp4/mp4io/mp4io.go b/format/mp4/mp4io/mp4io.go index 0227a843..f868d95e 100644 --- a/format/mp4/mp4io/mp4io.go +++ b/format/mp4/mp4io/mp4io.go @@ -2,7 +2,7 @@ package mp4io import ( - "github.com/nareix/joy4/utils/bits/pio" + "github.com/jinleileiking/joy4/utils/bits/pio" "os" "io" "fmt" diff --git a/format/mp4/muxer.go b/format/mp4/muxer.go index d1ef7e0c..c02bccab 100644 --- a/format/mp4/muxer.go +++ b/format/mp4/muxer.go @@ -3,11 +3,11 @@ package mp4 import ( "fmt" "time" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/h264parser" - "github.com/nareix/joy4/format/mp4/mp4io" - "github.com/nareix/joy4/utils/bits/pio" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/mp4/mp4io" + "github.com/jinleileiking/joy4/utils/bits/pio" "io" "bufio" ) diff --git a/format/mp4/stream.go b/format/mp4/stream.go index b837cd99..5889372a 100644 --- a/format/mp4/stream.go +++ b/format/mp4/stream.go @@ -1,8 +1,8 @@ package mp4 import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/format/mp4/mp4io" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/format/mp4/mp4io" "time" ) diff --git a/format/rtmp/rtmp.go b/format/rtmp/rtmp.go index d7cd56df..23da95f2 100644 --- a/format/rtmp/rtmp.go +++ b/format/rtmp/rtmp.go @@ -8,11 +8,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/nareix/joy4/utils/bits/pio" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/format/flv" - "github.com/nareix/joy4/format/flv/flvio" + "github.com/jinleileiking/joy4/utils/bits/pio" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/format/flv" + "github.com/jinleileiking/joy4/format/flv/flvio" "io" "net" "net/url" diff --git a/format/rtsp/client.go b/format/rtsp/client.go index 28f8592c..de5cf4cc 100644 --- a/format/rtsp/client.go +++ b/format/rtsp/client.go @@ -8,13 +8,13 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "github.com/nareix/joy4/utils/bits/pio" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" - "github.com/nareix/joy4/codec" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/h264parser" - "github.com/nareix/joy4/format/rtsp/sdp" + "github.com/jinleileiking/joy4/utils/bits/pio" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" + "github.com/jinleileiking/joy4/codec" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/rtsp/sdp" "io" "net" "net/textproto" diff --git a/format/rtsp/sdp/parser.go b/format/rtsp/sdp/parser.go index a092ddfc..ff69b006 100644 --- a/format/rtsp/sdp/parser.go +++ b/format/rtsp/sdp/parser.go @@ -4,7 +4,7 @@ import ( "encoding/base64" "encoding/hex" "fmt" - "github.com/nareix/joy4/av" + "github.com/jinleileiking/joy4/av" "strconv" "strings" ) diff --git a/format/rtsp/stream.go b/format/rtsp/stream.go index f3497cdb..8160270d 100644 --- a/format/rtsp/stream.go +++ b/format/rtsp/stream.go @@ -1,8 +1,8 @@ package rtsp import ( - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/format/rtsp/sdp" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/format/rtsp/sdp" "time" ) diff --git a/format/ts/demuxer.go b/format/ts/demuxer.go index df9c0cf1..1e2f9cd7 100644 --- a/format/ts/demuxer.go +++ b/format/ts/demuxer.go @@ -3,20 +3,32 @@ package ts import ( "bufio" "fmt" - "time" - "github.com/nareix/joy4/utils/bits/pio" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/format/ts/tsio" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/h264parser" "io" + "time" + + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/ts/tsio" + "github.com/jinleileiking/joy4/utils/bits/pio" ) +type TPayloadInfos struct { + Pts int + Dts int + PayloadInfo []byte +} + type Demuxer struct { r *bufio.Reader pkts []av.Packet + Pat *tsio.PAT + Pmt *tsio.PMT + Payloads [][]byte + PayloadInfos []TPayloadInfos + pat *tsio.PAT pmt *tsio.PMT streams []*Stream @@ -28,23 +40,29 @@ type Demuxer struct { func NewDemuxer(r io.Reader) *Demuxer { return &Demuxer{ tshdr: make([]byte, 188), - r: bufio.NewReaderSize(r, pio.RecommendBufioSize), + r: bufio.NewReaderSize(r, pio.RecommendBufioSize), } } func (self *Demuxer) Streams() (streams []av.CodecData, err error) { if err = self.probe(); err != nil { - return + // fmt.Println("probe error") + // spew.Dump("stream probe error", err) + // return } + + // dump streams to return for _, stream := range self.streams { streams = append(streams, stream.CodecData) } return } +// parse all data func (self *Demuxer) probe() (err error) { if self.stage == 0 { for { + //found pmt if self.pmt != nil { n := 0 for _, stream := range self.streams { @@ -101,7 +119,7 @@ func (self *Demuxer) initPMT(payload []byte) (err error) { return } self.pmt = &tsio.PMT{} - if _, err = self.pmt.Unmarshal(payload[psihdrlen:psihdrlen+datalen]); err != nil { + if _, err = self.pmt.Unmarshal(payload[psihdrlen : psihdrlen+datalen]); err != nil { return } @@ -112,6 +130,13 @@ func (self *Demuxer) initPMT(payload []byte) (err error) { stream.demuxer = self stream.pid = info.ElementaryPID stream.streamType = info.StreamType + if info.StreamType == 27 { + stream.streamTypeDes = "h264" + } else if info.StreamType == 15 { + stream.streamTypeDes = "avc" + } else { + stream.streamTypeDes = "other" + } switch info.StreamType { case tsio.ElementaryStreamTypeH264: self.streams = append(self.streams, stream) @@ -133,6 +158,7 @@ func (self *Demuxer) payloadEnd() (n int, err error) { return } +// find pat, pmt, and pes func (self *Demuxer) readTSPacket() (err error) { var hdrlen int var pid uint16 @@ -146,6 +172,8 @@ func (self *Demuxer) readTSPacket() (err error) { if pid, start, iskeyframe, hdrlen, err = tsio.ParseTSHeader(self.tshdr); err != nil { return } + + // fmt.Println("Got header") payload := self.tshdr[hdrlen:] if self.pat == nil { @@ -156,9 +184,11 @@ func (self *Demuxer) readTSPacket() (err error) { return } self.pat = &tsio.PAT{} - if _, err = self.pat.Unmarshal(payload[psihdrlen:psihdrlen+datalen]); err != nil { + if _, err = self.pat.Unmarshal(payload[psihdrlen : psihdrlen+datalen]); err != nil { return } + // fmt.Println("Got pat") + self.Pat = self.pat } } else if self.pmt == nil { for _, entry := range self.pat.Entries { @@ -166,6 +196,8 @@ func (self *Demuxer) readTSPacket() (err error) { if err = self.initPMT(payload); err != nil { return } + // fmt.Println("Got pmt") + self.Pmt = self.pmt break } } @@ -175,6 +207,7 @@ func (self *Demuxer) readTSPacket() (err error) { if err = stream.handleTSPacket(start, iskeyframe, payload); err != nil { return } + // fmt.Println("Got ts") break } } @@ -192,13 +225,13 @@ func (self *Stream) addPacket(payload []byte, timedelta time.Duration) { demuxer := self.demuxer pkt := av.Packet{ - Idx: int8(self.idx), + Idx: int8(self.idx), IsKeyFrame: self.iskeyframe, - Time: dts+timedelta, - Data: payload, + Time: dts + timedelta, + Data: payload, } if pts != dts { - pkt.CompositionTime = pts-dts + pkt.CompositionTime = pts - dts } demuxer.pkts = append(demuxer.pkts, pkt) } @@ -216,6 +249,12 @@ func (self *Stream) payloadEnd() (n int, err error) { switch self.streamType { case tsio.ElementaryStreamTypeAdtsAAC: + self.demuxer.Payloads = append(self.demuxer.Payloads, payload) + payload_info.PayloadInfo = payload + self.demuxer.PayloadInfos = append(self.demuxer.PayloadInfos, payload_info) + + // self.demuxer.PayloadInfos.PayloadInfo = append(self.demuxer.PayloadInfos.PayloadInfo, payload) + // fmt.Println("Payload aac end") var config aacparser.MPEG4AudioConfig delta := time.Duration(0) @@ -236,16 +275,28 @@ func (self *Stream) payloadEnd() (n int, err error) { } case tsio.ElementaryStreamTypeH264: + self.demuxer.Payloads = append(self.demuxer.Payloads, payload) + // self.demuxer.PayloadInfos.PayloadInfo = append(self.demuxer.PayloadInfos.PayloadInfo, payload) + payload_info.PayloadInfo = payload + self.demuxer.PayloadInfos = append(self.demuxer.PayloadInfos, payload_info) + + // fmt.Println("Payload h264 end") + // nalus, typ := h264parser.SplitNALUs(payload) nalus, _ := h264parser.SplitNALUs(payload) + + // spew.Dump(typ) var sps, pps []byte for _, nalu := range nalus { if len(nalu) > 0 { naltype := nalu[0] & 0x1f + // spew.Dump(naltype) switch { case naltype == 7: sps = nalu + // spew.Dump("got sps") case naltype == 8: pps = nalu + // spew.Dump("got pps") case h264parser.IsDataNALU(nalu): // raw nalu to avcc b := make([]byte, 4+len(nalu)) @@ -267,6 +318,9 @@ func (self *Stream) payloadEnd() (n int, err error) { return } +var total int +var payload_info TPayloadInfos + func (self *Stream) handleTSPacket(start bool, iskeyframe bool, payload []byte) (err error) { if start { if _, err = self.payloadEnd(); err != nil { @@ -276,6 +330,8 @@ func (self *Stream) handleTSPacket(start bool, iskeyframe bool, payload []byte) if hdrlen, _, self.datalen, self.pts, self.dts, err = tsio.ParsePESHeader(payload); err != nil { return } + payload_info.Pts = int(self.pts) + payload_info.Dts = int(self.dts) self.iskeyframe = iskeyframe if self.datalen == 0 { self.data = make([]byte, 0, 4096) @@ -286,5 +342,7 @@ func (self *Stream) handleTSPacket(start bool, iskeyframe bool, payload []byte) } else { self.data = append(self.data, payload...) } + total = total + 1 + // spew.Dump(total) return } diff --git a/format/ts/handler.go b/format/ts/handler.go index 068ddf97..b5f92ea3 100644 --- a/format/ts/handler.go +++ b/format/ts/handler.go @@ -2,8 +2,9 @@ package ts import ( "io" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/av/avutil" + + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/av/avutil" ) func Handler(h *avutil.RegisterHandler) { @@ -13,6 +14,7 @@ func Handler(h *avutil.RegisterHandler) { return b[0] == 0x47 && b[188] == 0x47 } + // fmt.Println("found ts") h.ReaderDemuxer = func(r io.Reader) av.Demuxer { return NewDemuxer(r) } @@ -23,4 +25,3 @@ func Handler(h *avutil.RegisterHandler) { h.CodecTypes = CodecTypes } - diff --git a/format/ts/muxer.go b/format/ts/muxer.go index 030a1c13..55a6c213 100644 --- a/format/ts/muxer.go +++ b/format/ts/muxer.go @@ -2,10 +2,10 @@ package ts import ( "fmt" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/codec/aacparser" - "github.com/nareix/joy4/codec/h264parser" - "github.com/nareix/joy4/format/ts/tsio" + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/codec/aacparser" + "github.com/jinleileiking/joy4/codec/h264parser" + "github.com/jinleileiking/joy4/format/ts/tsio" "io" "time" ) diff --git a/format/ts/stream.go b/format/ts/stream.go index 36b8831f..19d48835 100644 --- a/format/ts/stream.go +++ b/format/ts/stream.go @@ -2,8 +2,9 @@ package ts import ( "time" - "github.com/nareix/joy4/av" - "github.com/nareix/joy4/format/ts/tsio" + + "github.com/jinleileiking/joy4/av" + "github.com/jinleileiking/joy4/format/ts/tsio" ) type Stream struct { @@ -12,16 +13,16 @@ type Stream struct { demuxer *Demuxer muxer *Muxer - pid uint16 - streamId uint8 - streamType uint8 + pid uint16 + streamId uint8 + streamType uint8 + streamTypeDes string - tsw *tsio.TSWriter - idx int + tsw *tsio.TSWriter + idx int iskeyframe bool - pts, dts time.Duration - data []byte - datalen int + pts, dts time.Duration + data []byte + datalen int } - diff --git a/format/ts/tsio/tsio.go b/format/ts/tsio/tsio.go index ee4563ed..a02b51ff 100644 --- a/format/ts/tsio/tsio.go +++ b/format/ts/tsio/tsio.go @@ -1,11 +1,11 @@ - package tsio import ( + "fmt" "io" "time" - "fmt" - "github.com/nareix/joy4/utils/bits/pio" + + "github.com/jinleileiking/joy4/utils/bits/pio" ) const ( @@ -48,7 +48,7 @@ type PAT struct { } func (self PAT) Len() (n int) { - return len(self.Entries)*4 + return len(self.Entries) * 4 } func (self PAT) Marshal(b []byte) (n int) { @@ -73,10 +73,10 @@ func (self *PAT) Unmarshal(b []byte) (n int, err error) { entry.ProgramNumber = pio.U16BE(b[n:]) n += 2 if entry.ProgramNumber == 0 { - entry.NetworkPID = pio.U16BE(b[n:])&0x1fff + entry.NetworkPID = pio.U16BE(b[n:]) & 0x1fff n += 2 } else { - entry.ProgramMapPID = pio.U16BE(b[n:])&0x1fff + entry.ProgramMapPID = pio.U16BE(b[n:]) & 0x1fff n += 2 } self.Entries = append(self.Entries, entry) @@ -98,6 +98,7 @@ type Descriptor struct { type ElementaryStreamInfo struct { StreamType uint8 + StreamTypeDes string ElementaryPID uint16 Descriptors []Descriptor } @@ -117,7 +118,7 @@ func (self PMT) Len() (n int) { n += 2 for _, desc := range self.ProgramDescriptors { - n += 2+len(desc.Data) + n += 2 + len(desc.Data) } for _, info := range self.ElementaryStreamInfos { @@ -133,7 +134,7 @@ func (self PMT) Len() (n int) { n += 2 for _, desc := range info.Descriptors { - n += 2+len(desc.Data) + n += 2 + len(desc.Data) } } @@ -162,7 +163,7 @@ func (self PMT) Marshal(b []byte) (n int) { n += 2 pos := n n += self.fillDescs(b[n:], self.ProgramDescriptors) - desclen := n-pos + desclen := n - pos pio.PutU16BE(b[hold:], uint16(desclen)|0xf<<12) for _, info := range self.ElementaryStreamInfos { @@ -178,7 +179,7 @@ func (self PMT) Marshal(b []byte) (n int) { n += 2 pos := n n += self.fillDescs(b[n:], info.Descriptors) - desclen := n-pos + desclen := n - pos pio.PutU16BE(b[hold:], uint16(desclen)|0x3c<<10) } @@ -219,13 +220,13 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) { // 111(3) // PCRPID(13) - self.PCRPID = pio.U16BE(b[0:2])&0x1fff + self.PCRPID = pio.U16BE(b[0:2]) & 0x1fff n += 2 // Reserved(4)=0xf // Reserved(2)=0x0 // Program info length(10) - desclen := int(pio.U16BE(b[2:4])&0x3ff) + desclen := int(pio.U16BE(b[2:4]) & 0x3ff) n += 2 if desclen > 0 { @@ -233,7 +234,7 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) { err = ErrParsePMT return } - if self.ProgramDescriptors, err = self.parseDescs(b[n:n+desclen]); err != nil { + if self.ProgramDescriptors, err = self.parseDescs(b[n : n+desclen]); err != nil { return } n += desclen @@ -247,16 +248,23 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) { var info ElementaryStreamInfo info.StreamType = b[n] + if info.StreamType == 0x0f { + info.StreamTypeDes = "aac" + } else if info.StreamType == 0x1b { + info.StreamTypeDes = "h264" + } else { + info.StreamTypeDes = "other" + } n++ // Reserved(3) // Elementary PID(13) - info.ElementaryPID = pio.U16BE(b[n:])&0x1fff + info.ElementaryPID = pio.U16BE(b[n:]) & 0x1fff n += 2 // Reserved(6) // ES Info length(10) - desclen := int(pio.U16BE(b[n:])&0x3ff) + desclen := int(pio.U16BE(b[n:]) & 0x3ff) n += 2 if desclen > 0 { @@ -264,7 +272,7 @@ func (self *PMT) Unmarshal(b []byte) (n int, err error) { err = ErrParsePMT return } - if info.Descriptors, err = self.parseDescs(b[n:n+desclen]); err != nil { + if info.Descriptors, err = self.parseDescs(b[n : n+desclen]); err != nil { return } n += desclen @@ -345,7 +353,7 @@ func FillPSI(h []byte, tableid uint8, tableext uint16, datalen int) (n int) { n++ // section_syntax_indicator(1)=1,private_bit(1)=0,reserved(2)=3,unused(2)=0,section_length(10) - pio.PutU16BE(h[n:], uint16(0xa<<12 | 2+3+4+datalen)) + pio.PutU16BE(h[n:], uint16(0xa<<12|2+3+4+datalen)) n += 2 // Table ID extension(16) @@ -375,7 +383,7 @@ func FillPSI(h []byte, tableid uint8, tableext uint16, datalen int) (n int) { func TimeToPCR(tm time.Duration) (pcr uint64) { // base(33)+resverd(6)+ext(9) - ts := uint64(tm*PCR_HZ/time.Second) + ts := uint64(tm * PCR_HZ / time.Second) base := ts / 300 ext := ts % 300 pcr = base<<15 | 0x3f<<9 | ext @@ -386,12 +394,12 @@ func PCRToTime(pcr uint64) (tm time.Duration) { base := pcr >> 15 ext := pcr & 0x1ff ts := base*300 + ext - tm = time.Duration(ts)*time.Second/time.Duration(PCR_HZ) + tm = time.Duration(ts) * time.Second / time.Duration(PCR_HZ) return } func TimeToTs(tm time.Duration) (v uint64) { - ts := uint64(tm*PTS_HZ/time.Second) + ts := uint64(tm * PTS_HZ / time.Second) // 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1 v = ((ts>>30)&0x7)<<33 | ((ts>>15)&0x7fff)<<17 | (ts&0x7fff)<<1 | 0x100010001 return @@ -399,8 +407,8 @@ func TimeToTs(tm time.Duration) (v uint64) { func TsToTime(v uint64) (tm time.Duration) { // 0010 PTS 32..30 1 PTS 29..15 1 PTS 14..00 1 - ts := (((v>>33)&0x7)<<30) | (((v>>17)&0x7fff) << 15) | ((v>>1)&0x7fff) - tm = time.Duration(ts)*time.Second/time.Duration(PTS_HZ) + ts := (((v >> 33) & 0x7) << 30) | (((v >> 17) & 0x7fff) << 15) | ((v >> 1) & 0x7fff) + tm = time.Duration(ts) * time.Second / time.Duration(PTS_HZ) return } @@ -415,13 +423,14 @@ func ParsePESHeader(h []byte) (hdrlen int, streamid uint8, datalen int, pts, dts return } streamid = h[3] + // spew.Printf("streamid %x", streamid) flags := h[7] - hdrlen = int(h[8])+9 + hdrlen = int(h[8]) + 9 datalen = int(pio.U16BE(h[4:6])) if datalen > 0 { - datalen -= int(h[8])+3 + datalen -= int(h[8]) + 3 } const PTS = 1 << 7 @@ -433,12 +442,14 @@ func ParsePESHeader(h []byte) (hdrlen int, streamid uint8, datalen int, pts, dts return } pts = TsToTime(pio.U40BE(h[9:14])) + // spew.Dump("pts", pts) if flags&DTS != 0 { if len(h) < 19 { err = ErrPESHeader return } dts = TsToTime(pio.U40BE(h[14:19])) + // spew.Dump("dts", dts) } } @@ -479,7 +490,7 @@ func FillPESHeader(h []byte, streamid uint8, datalen int, pts, dts time.Duration } pio.PutU16BE(h[4:6], pktlen) - h[6] = 2<<6|1 // resverd(6,2)=2,original_or_copy(0,1)=1 + h[6] = 2<<6 | 1 // resverd(6,2)=2,original_or_copy(0,1)=1 h[7] = flags h[8] = uint8(n) @@ -499,9 +510,9 @@ func FillPESHeader(h []byte, streamid uint8, datalen int, pts, dts time.Duration } type TSWriter struct { - w io.Writer + w io.Writer ContinuityCounter uint - tshdr []byte + tshdr []byte } func NewTSWriter(pid uint16) *TSWriter { @@ -521,21 +532,21 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio writepos := 0 for writepos < datavlen { - self.tshdr[1] = self.tshdr[1]&0x1f - self.tshdr[3] = byte(self.ContinuityCounter)&0xf|0x30 + self.tshdr[1] = self.tshdr[1] & 0x1f + self.tshdr[3] = byte(self.ContinuityCounter)&0xf | 0x30 self.tshdr[5] = 0 // flags hdrlen := 6 self.ContinuityCounter++ if writepos == 0 { - self.tshdr[1] = 0x40|self.tshdr[1] // Payload Unit Start Indicator + self.tshdr[1] = 0x40 | self.tshdr[1] // Payload Unit Start Indicator if pcr != 0 { hdrlen += 6 - self.tshdr[5] = 0x10|self.tshdr[5] // PCR flag (Discontinuity indicator 0x80) + self.tshdr[5] = 0x10 | self.tshdr[5] // PCR flag (Discontinuity indicator 0x80) pio.PutU48BE(self.tshdr[6:12], TimeToPCR(pcr)) } if sync { - self.tshdr[5] = 0x40|self.tshdr[5] // Random Access indicator + self.tshdr[5] = 0x40 | self.tshdr[5] // Random Access indicator } } @@ -551,7 +562,7 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio } n := pio.VecSliceTo(datav, writev, writepos, end) - self.tshdr[4] = byte(hdrlen)-5 // length + self.tshdr[4] = byte(hdrlen) - 5 // length if _, err = w.Write(self.tshdr[:hdrlen]); err != nil { return } @@ -561,7 +572,7 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio } } if padtail > 0 { - if _, err = w.Write(self.tshdr[188-padtail:188]); err != nil { + if _, err = w.Write(self.tshdr[188-padtail : 188]); err != nil { return } } @@ -578,13 +589,12 @@ func ParseTSHeader(tshdr []byte) (pid uint16, start bool, iskeyframe bool, hdrle err = fmt.Errorf("tshdr sync invalid") return } - pid = uint16((tshdr[1]&0x1f))<<8|uint16(tshdr[2]) + pid = uint16((tshdr[1]&0x1f))<<8 | uint16(tshdr[2]) start = tshdr[1]&0x40 != 0 hdrlen += 4 if tshdr[3]&0x20 != 0 { - hdrlen += int(tshdr[4])+1 + hdrlen += int(tshdr[4]) + 1 iskeyframe = tshdr[5]&0x40 != 0 } return } -