work HEVC in progress
This commit is contained in:
		| @@ -1,7 +1,10 @@ | |||||||
| package mp4io | package mp4io | ||||||
|  |  | ||||||
| import "github.com/deepch/vdk/utils/bits/pio" | import ( | ||||||
| import "time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/deepch/vdk/utils/bits/pio" | ||||||
|  | ) | ||||||
|  |  | ||||||
| const MOOF = Tag(0x6d6f6f66) | const MOOF = Tag(0x6d6f6f66) | ||||||
|  |  | ||||||
| @@ -21,6 +24,17 @@ func (self AVC1Desc) Tag() Tag { | |||||||
| 	return AVC1 | 	return AVC1 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //0x31766568 | ||||||
|  | const HEV1 = Tag(0x68766331) | ||||||
|  |  | ||||||
|  | func (self HV1Desc) Tag() Tag { | ||||||
|  | 	return HEV1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //const HVC1 = Tag(0x68766331) | ||||||
|  | //func (self HVC1Desc) Tag() Tag { | ||||||
|  | //	return HVC1 | ||||||
|  | //} | ||||||
| const URL = Tag(0x75726c20) | const URL = Tag(0x75726c20) | ||||||
|  |  | ||||||
| func (self DataReferUrl) Tag() Tag { | func (self DataReferUrl) Tag() Tag { | ||||||
| @@ -153,6 +167,12 @@ func (self AVC1Conf) Tag() Tag { | |||||||
| 	return AVCC | 	return AVCC | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const HVCC = Tag(0x68766343) | ||||||
|  |  | ||||||
|  | func (self HV1Conf) Tag() Tag { | ||||||
|  | 	return HVCC | ||||||
|  | } | ||||||
|  |  | ||||||
| const TFDT = Tag(0x74666474) | const TFDT = Tag(0x74666474) | ||||||
|  |  | ||||||
| func (self TrackFragDecodeTime) Tag() Tag { | func (self TrackFragDecodeTime) Tag() Tag { | ||||||
| @@ -1682,6 +1702,7 @@ func (self SampleTable) Children() (r []Atom) { | |||||||
| type SampleDesc struct { | type SampleDesc struct { | ||||||
| 	Version  uint8 | 	Version  uint8 | ||||||
| 	AVC1Desc *AVC1Desc | 	AVC1Desc *AVC1Desc | ||||||
|  | 	HV1Desc  *HV1Desc | ||||||
| 	MP4ADesc *MP4ADesc | 	MP4ADesc *MP4ADesc | ||||||
| 	Unknowns []Atom | 	Unknowns []Atom | ||||||
| 	AtomPos | 	AtomPos | ||||||
| @@ -1701,6 +1722,9 @@ func (self SampleDesc) marshal(b []byte) (n int) { | |||||||
| 	if self.AVC1Desc != nil { | 	if self.AVC1Desc != nil { | ||||||
| 		_childrenNR++ | 		_childrenNR++ | ||||||
| 	} | 	} | ||||||
|  | 	if self.HV1Desc != nil { | ||||||
|  | 		_childrenNR++ | ||||||
|  | 	} | ||||||
| 	if self.MP4ADesc != nil { | 	if self.MP4ADesc != nil { | ||||||
| 		_childrenNR++ | 		_childrenNR++ | ||||||
| 	} | 	} | ||||||
| @@ -1710,6 +1734,9 @@ func (self SampleDesc) marshal(b []byte) (n int) { | |||||||
| 	if self.AVC1Desc != nil { | 	if self.AVC1Desc != nil { | ||||||
| 		n += self.AVC1Desc.Marshal(b[n:]) | 		n += self.AVC1Desc.Marshal(b[n:]) | ||||||
| 	} | 	} | ||||||
|  | 	if self.HV1Desc != nil { | ||||||
|  | 		n += self.HV1Desc.Marshal(b[n:]) | ||||||
|  | 	} | ||||||
| 	if self.MP4ADesc != nil { | 	if self.MP4ADesc != nil { | ||||||
| 		n += self.MP4ADesc.Marshal(b[n:]) | 		n += self.MP4ADesc.Marshal(b[n:]) | ||||||
| 	} | 	} | ||||||
| @@ -1726,6 +1753,9 @@ func (self SampleDesc) Len() (n int) { | |||||||
| 	if self.AVC1Desc != nil { | 	if self.AVC1Desc != nil { | ||||||
| 		n += self.AVC1Desc.Len() | 		n += self.AVC1Desc.Len() | ||||||
| 	} | 	} | ||||||
|  | 	if self.HV1Desc != nil { | ||||||
|  | 		n += self.HV1Desc.Len() | ||||||
|  | 	} | ||||||
| 	if self.MP4ADesc != nil { | 	if self.MP4ADesc != nil { | ||||||
| 		n += self.MP4ADesc.Len() | 		n += self.MP4ADesc.Len() | ||||||
| 	} | 	} | ||||||
| @@ -1762,6 +1792,15 @@ func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err error) { | |||||||
| 				} | 				} | ||||||
| 				self.AVC1Desc = atom | 				self.AVC1Desc = atom | ||||||
| 			} | 			} | ||||||
|  | 		case HEV1: | ||||||
|  | 			{ | ||||||
|  | 				atom := &HV1Desc{} | ||||||
|  | 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil { | ||||||
|  | 					err = parseErr("hec1", n+offset, err) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 				self.HV1Desc = atom | ||||||
|  | 			} | ||||||
| 		case MP4A: | 		case MP4A: | ||||||
| 			{ | 			{ | ||||||
| 				atom := &MP4ADesc{} | 				atom := &MP4ADesc{} | ||||||
| @@ -1789,6 +1828,9 @@ func (self SampleDesc) Children() (r []Atom) { | |||||||
| 	if self.AVC1Desc != nil { | 	if self.AVC1Desc != nil { | ||||||
| 		r = append(r, self.AVC1Desc) | 		r = append(r, self.AVC1Desc) | ||||||
| 	} | 	} | ||||||
|  | 	if self.HV1Desc != nil { | ||||||
|  | 		r = append(r, self.HV1Desc) | ||||||
|  | 	} | ||||||
| 	if self.MP4ADesc != nil { | 	if self.MP4ADesc != nil { | ||||||
| 		r = append(r, self.MP4ADesc) | 		r = append(r, self.MP4ADesc) | ||||||
| 	} | 	} | ||||||
| @@ -1955,6 +1997,25 @@ func (self MP4ADesc) Children() (r []Atom) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type HV1Desc struct { | ||||||
|  | 	DataRefIdx           int16 | ||||||
|  | 	Version              int16 | ||||||
|  | 	Revision             int16 | ||||||
|  | 	Vendor               int32 | ||||||
|  | 	TemporalQuality      int32 | ||||||
|  | 	SpatialQuality       int32 | ||||||
|  | 	Width                int16 | ||||||
|  | 	Height               int16 | ||||||
|  | 	HorizontalResolution float64 | ||||||
|  | 	VorizontalResolution float64 | ||||||
|  | 	FrameCount           int16 | ||||||
|  | 	CompressorName       [32]byte | ||||||
|  | 	Depth                int16 | ||||||
|  | 	ColorTableId         int16 | ||||||
|  | 	Conf                 *HV1Conf | ||||||
|  | 	Unknowns             []Atom | ||||||
|  | 	AtomPos | ||||||
|  | } | ||||||
| type AVC1Desc struct { | type AVC1Desc struct { | ||||||
| 	DataRefIdx           int16 | 	DataRefIdx           int16 | ||||||
| 	Version              int16 | 	Version              int16 | ||||||
| @@ -1981,6 +2042,12 @@ func (self AVC1Desc) Marshal(b []byte) (n int) { | |||||||
| 	pio.PutU32BE(b[0:], uint32(n)) | 	pio.PutU32BE(b[0:], uint32(n)) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | func (self HV1Desc) Marshal(b []byte) (n int) { | ||||||
|  | 	pio.PutU32BE(b[4:], uint32(HEV1)) | ||||||
|  | 	n += self.marshal(b[8:]) + 8 | ||||||
|  | 	pio.PutU32BE(b[0:], uint32(n)) | ||||||
|  | 	return | ||||||
|  | } | ||||||
| func (self AVC1Desc) marshal(b []byte) (n int) { | func (self AVC1Desc) marshal(b []byte) (n int) { | ||||||
| 	n += 6 | 	n += 6 | ||||||
| 	pio.PutI16BE(b[n:], self.DataRefIdx) | 	pio.PutI16BE(b[n:], self.DataRefIdx) | ||||||
| @@ -2020,6 +2087,45 @@ func (self AVC1Desc) marshal(b []byte) (n int) { | |||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | func (self HV1Desc) marshal(b []byte) (n int) { | ||||||
|  | 	n += 6 | ||||||
|  | 	pio.PutI16BE(b[n:], self.DataRefIdx) | ||||||
|  | 	n += 2 | ||||||
|  | 	pio.PutI16BE(b[n:], self.Version) | ||||||
|  | 	n += 2 | ||||||
|  | 	pio.PutI16BE(b[n:], self.Revision) | ||||||
|  | 	n += 2 | ||||||
|  | 	pio.PutI32BE(b[n:], self.Vendor) | ||||||
|  | 	n += 4 | ||||||
|  | 	pio.PutI32BE(b[n:], self.TemporalQuality) | ||||||
|  | 	n += 4 | ||||||
|  | 	pio.PutI32BE(b[n:], self.SpatialQuality) | ||||||
|  | 	n += 4 | ||||||
|  | 	pio.PutI16BE(b[n:], self.Width) | ||||||
|  | 	n += 2 | ||||||
|  | 	pio.PutI16BE(b[n:], self.Height) | ||||||
|  | 	n += 2 | ||||||
|  | 	PutFixed32(b[n:], self.HorizontalResolution) | ||||||
|  | 	n += 4 | ||||||
|  | 	PutFixed32(b[n:], self.VorizontalResolution) | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	pio.PutI16BE(b[n:], self.FrameCount) | ||||||
|  | 	n += 2 | ||||||
|  | 	copy(b[n:], self.CompressorName[:]) | ||||||
|  | 	n += len(self.CompressorName[:]) | ||||||
|  | 	pio.PutI16BE(b[n:], self.Depth) | ||||||
|  | 	n += 2 | ||||||
|  | 	pio.PutI16BE(b[n:], self.ColorTableId) | ||||||
|  | 	n += 2 | ||||||
|  | 	if self.Conf != nil { | ||||||
|  | 		n += self.Conf.Marshal(b[n:]) | ||||||
|  | 	} | ||||||
|  | 	for _, atom := range self.Unknowns { | ||||||
|  | 		n += atom.Marshal(b[n:]) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
| func (self AVC1Desc) Len() (n int) { | func (self AVC1Desc) Len() (n int) { | ||||||
| 	n += 8 | 	n += 8 | ||||||
| 	n += 6 | 	n += 6 | ||||||
| @@ -2046,6 +2152,32 @@ func (self AVC1Desc) Len() (n int) { | |||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | func (self HV1Desc) Len() (n int) { | ||||||
|  | 	n += 8 | ||||||
|  | 	n += 6 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 2 | ||||||
|  | 	n += len(self.CompressorName[:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	n += 2 | ||||||
|  | 	if self.Conf != nil { | ||||||
|  | 		n += self.Conf.Len() | ||||||
|  | 	} | ||||||
|  | 	for _, atom := range self.Unknowns { | ||||||
|  | 		n += atom.Len() | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
| func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) { | func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) { | ||||||
| 	(&self.AtomPos).setPos(offset, len(b)) | 	(&self.AtomPos).setPos(offset, len(b)) | ||||||
| 	n += 8 | 	n += 8 | ||||||
| @@ -2166,6 +2298,126 @@ func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) { | |||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | func (self *HV1Desc) Unmarshal(b []byte, offset int) (n int, err error) { | ||||||
|  | 	(&self.AtomPos).setPos(offset, len(b)) | ||||||
|  | 	n += 8 | ||||||
|  | 	n += 6 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("DataRefIdx", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.DataRefIdx = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("Version", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Version = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("Revision", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Revision = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+4 { | ||||||
|  | 		err = parseErr("Vendor", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Vendor = pio.I32BE(b[n:]) | ||||||
|  | 	n += 4 | ||||||
|  | 	if len(b) < n+4 { | ||||||
|  | 		err = parseErr("TemporalQuality", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.TemporalQuality = pio.I32BE(b[n:]) | ||||||
|  | 	n += 4 | ||||||
|  | 	if len(b) < n+4 { | ||||||
|  | 		err = parseErr("SpatialQuality", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.SpatialQuality = pio.I32BE(b[n:]) | ||||||
|  | 	n += 4 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("Width", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Width = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("Height", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Height = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+4 { | ||||||
|  | 		err = parseErr("HorizontalResolution", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.HorizontalResolution = GetFixed32(b[n:]) | ||||||
|  | 	n += 4 | ||||||
|  | 	if len(b) < n+4 { | ||||||
|  | 		err = parseErr("VorizontalResolution", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.VorizontalResolution = GetFixed32(b[n:]) | ||||||
|  | 	n += 4 | ||||||
|  | 	n += 4 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("FrameCount", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.FrameCount = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+len(self.CompressorName) { | ||||||
|  | 		err = parseErr("CompressorName", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	copy(self.CompressorName[:], b[n:]) | ||||||
|  | 	n += len(self.CompressorName) | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("Depth", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.Depth = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	if len(b) < n+2 { | ||||||
|  | 		err = parseErr("ColorTableId", n+offset, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	self.ColorTableId = pio.I16BE(b[n:]) | ||||||
|  | 	n += 2 | ||||||
|  | 	for n+8 < len(b) { | ||||||
|  | 		tag := Tag(pio.U32BE(b[n+4:])) | ||||||
|  | 		size := int(pio.U32BE(b[n:])) | ||||||
|  | 		if len(b) < n+size { | ||||||
|  | 			err = parseErr("TagSizeInvalid", n+offset, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		switch tag { | ||||||
|  | 		case HVCC: | ||||||
|  | 			{ | ||||||
|  | 				atom := &HV1Conf{} | ||||||
|  | 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil { | ||||||
|  | 					err = parseErr("hvcC", n+offset, err) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 				self.Conf = atom | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			{ | ||||||
|  | 				atom := &Dummy{Tag_: tag, Data: b[n : n+size]} | ||||||
|  | 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil { | ||||||
|  | 					err = parseErr("", n+offset, err) | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 				self.Unknowns = append(self.Unknowns, atom) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		n += size | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
| func (self AVC1Desc) Children() (r []Atom) { | func (self AVC1Desc) Children() (r []Atom) { | ||||||
| 	if self.Conf != nil { | 	if self.Conf != nil { | ||||||
| 		r = append(r, self.Conf) | 		r = append(r, self.Conf) | ||||||
| @@ -2173,12 +2425,24 @@ func (self AVC1Desc) Children() (r []Atom) { | |||||||
| 	r = append(r, self.Unknowns...) | 	r = append(r, self.Unknowns...) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | func (self HV1Desc) Children() (r []Atom) { | ||||||
|  | 	if self.Conf != nil { | ||||||
|  | 		r = append(r, self.Conf) | ||||||
|  | 	} | ||||||
|  | 	r = append(r, self.Unknowns...) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| type AVC1Conf struct { | type AVC1Conf struct { | ||||||
| 	Data []byte | 	Data []byte | ||||||
| 	AtomPos | 	AtomPos | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type HV1Conf struct { | ||||||
|  | 	Data []byte | ||||||
|  | 	AtomPos | ||||||
|  | } | ||||||
|  |  | ||||||
| func (self AVC1Conf) Marshal(b []byte) (n int) { | func (self AVC1Conf) Marshal(b []byte) (n int) { | ||||||
| 	pio.PutU32BE(b[4:], uint32(AVCC)) | 	pio.PutU32BE(b[4:], uint32(AVCC)) | ||||||
| 	n += self.marshal(b[8:]) + 8 | 	n += self.marshal(b[8:]) + 8 | ||||||
| @@ -2206,6 +2470,36 @@ func (self AVC1Conf) Children() (r []Atom) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | HVEC | ||||||
|  | */ | ||||||
|  | func (self HV1Conf) Marshal(b []byte) (n int) { | ||||||
|  | 	pio.PutU32BE(b[4:], uint32(HVCC)) | ||||||
|  | 	n += self.marshal(b[8:]) + 8 | ||||||
|  | 	pio.PutU32BE(b[0:], uint32(n)) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | func (self HV1Conf) marshal(b []byte) (n int) { | ||||||
|  | 	copy(b[n:], self.Data[:]) | ||||||
|  | 	n += len(self.Data[:]) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | func (self HV1Conf) Len() (n int) { | ||||||
|  | 	n += 8 | ||||||
|  | 	n += len(self.Data[:]) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | func (self *HV1Conf) Unmarshal(b []byte, offset int) (n int, err error) { | ||||||
|  | 	(&self.AtomPos).setPos(offset, len(b)) | ||||||
|  | 	n += 8 | ||||||
|  | 	self.Data = b[n:] | ||||||
|  | 	n += len(b[n:]) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | func (self HV1Conf) Children() (r []Atom) { | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| type TimeToSample struct { | type TimeToSample struct { | ||||||
| 	Version uint8 | 	Version uint8 | ||||||
| 	Flags   uint32 | 	Flags   uint32 | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ func NewMuxer(w io.WriteSeeker) *Muxer { | |||||||
|  |  | ||||||
| func (self *Muxer) newStream(codec av.CodecData) (err error) { | func (self *Muxer) newStream(codec av.CodecData) (err error) { | ||||||
| 	switch codec.Type() { | 	switch codec.Type() { | ||||||
| 	case av.H264, av.AAC: | 	case av.H264, av.H265, av.AAC: | ||||||
|  |  | ||||||
| 	default: | 	default: | ||||||
| 		err = fmt.Errorf("mp4: codec type=%v is not supported", codec.Type()) | 		err = fmt.Errorf("mp4: codec type=%v is not supported", codec.Type()) | ||||||
| @@ -82,6 +82,8 @@ func (self *Muxer) newStream(codec av.CodecData) (err error) { | |||||||
| 	switch codec.Type() { | 	switch codec.Type() { | ||||||
| 	case av.H264: | 	case av.H264: | ||||||
| 		stream.sample.SyncSample = &mp4io.SyncSample{} | 		stream.sample.SyncSample = &mp4io.SyncSample{} | ||||||
|  | 	case av.H265: | ||||||
|  | 		stream.sample.SyncSample = &mp4io.SyncSample{} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	stream.timeScale = 90000 | 	stream.timeScale = 90000 | ||||||
| @@ -94,7 +96,6 @@ func (self *Muxer) newStream(codec av.CodecData) (err error) { | |||||||
| func (self *Stream) fillTrackAtom() (err error) { | func (self *Stream) fillTrackAtom() (err error) { | ||||||
| 	self.trackAtom.Media.Header.TimeScale = int32(self.timeScale) | 	self.trackAtom.Media.Header.TimeScale = int32(self.timeScale) | ||||||
| 	self.trackAtom.Media.Header.Duration = int32(self.duration) | 	self.trackAtom.Media.Header.Duration = int32(self.duration) | ||||||
|  |  | ||||||
| 	if self.Type() == av.H264 { | 	if self.Type() == av.H264 { | ||||||
| 		codec := self.CodecData.(h264parser.CodecData) | 		codec := self.CodecData.(h264parser.CodecData) | ||||||
| 		width, height := codec.Width(), codec.Height() | 		width, height := codec.Width(), codec.Height() | ||||||
| @@ -118,7 +119,29 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 		} | 		} | ||||||
| 		self.trackAtom.Header.TrackWidth = float64(width) | 		self.trackAtom.Header.TrackWidth = float64(width) | ||||||
| 		self.trackAtom.Header.TrackHeight = float64(height) | 		self.trackAtom.Header.TrackHeight = float64(height) | ||||||
|  | 	} else if self.Type() == av.H265 { | ||||||
|  | 		codec := self.CodecData.(h264parser.CodecData) | ||||||
|  | 		width, height := codec.Width(), codec.Height() | ||||||
|  | 		self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{ | ||||||
|  | 			DataRefIdx:           1, | ||||||
|  | 			HorizontalResolution: 72, | ||||||
|  | 			VorizontalResolution: 72, | ||||||
|  | 			Width:                int16(width), | ||||||
|  | 			Height:               int16(height), | ||||||
|  | 			FrameCount:           1, | ||||||
|  | 			Depth:                24, | ||||||
|  | 			ColorTableId:         -1, | ||||||
|  | 			Conf:                 &mp4io.HV1Conf{Data: codec.AVCDecoderConfRecordBytes()}, | ||||||
|  | 		} | ||||||
|  | 		self.trackAtom.Media.Handler = &mp4io.HandlerRefer{ | ||||||
|  | 			SubType: [4]byte{'v', 'i', 'd', 'e'}, | ||||||
|  | 			Name:    []byte("Video Media Handler"), | ||||||
|  | 		} | ||||||
|  | 		self.trackAtom.Media.Info.Video = &mp4io.VideoMediaInfo{ | ||||||
|  | 			Flags: 0x000001, | ||||||
|  | 		} | ||||||
|  | 		self.trackAtom.Header.TrackWidth = float64(width) | ||||||
|  | 		self.trackAtom.Header.TrackHeight = float64(height) | ||||||
| 	} else if self.Type() == av.AAC { | 	} else if self.Type() == av.AAC { | ||||||
| 		codec := self.CodecData.(aacparser.CodecData) | 		codec := self.CodecData.(aacparser.CodecData) | ||||||
| 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ func (self *Muxer) SetMaxFrames(count int) { | |||||||
| } | } | ||||||
| func (self *Muxer) newStream(codec av.CodecData) (err error) { | func (self *Muxer) newStream(codec av.CodecData) (err error) { | ||||||
| 	switch codec.Type() { | 	switch codec.Type() { | ||||||
| 	case av.H264, av.AAC: | 	case av.H264, av.H265, av.AAC: | ||||||
| 	default: | 	default: | ||||||
| 		err = fmt.Errorf("fmp4: codec type=%v is not supported", codec.Type()) | 		err = fmt.Errorf("fmp4: codec type=%v is not supported", codec.Type()) | ||||||
| 		return | 		return | ||||||
| @@ -78,6 +78,9 @@ func (self *Muxer) newStream(codec av.CodecData) (err error) { | |||||||
| 	case av.H264: | 	case av.H264: | ||||||
| 		stream.sample.SyncSample = &mp4io.SyncSample{} | 		stream.sample.SyncSample = &mp4io.SyncSample{} | ||||||
| 		stream.timeScale = 90000 | 		stream.timeScale = 90000 | ||||||
|  | 	case av.H265: | ||||||
|  | 		stream.sample.SyncSample = &mp4io.SyncSample{} | ||||||
|  | 		stream.timeScale = 90000 | ||||||
| 	case av.AAC: | 	case av.AAC: | ||||||
| 		stream.timeScale = int64(codec.(av.AudioCodecData).SampleRate()) | 		stream.timeScale = int64(codec.(av.AudioCodecData).SampleRate()) | ||||||
| 	} | 	} | ||||||
| @@ -174,6 +177,28 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 			Flags: 0x000001, | 			Flags: 0x000001, | ||||||
| 		} | 		} | ||||||
| 		self.codecString = fmt.Sprintf("avc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | 		self.codecString = fmt.Sprintf("avc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | ||||||
|  | 	} else if self.Type() == av.H265 { | ||||||
|  | 		codec := self.CodecData.(h264parser.CodecData) | ||||||
|  | 		width, height := codec.Width(), codec.Height() | ||||||
|  | 		self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{ | ||||||
|  | 			DataRefIdx:           1, | ||||||
|  | 			HorizontalResolution: 72, | ||||||
|  | 			VorizontalResolution: 72, | ||||||
|  | 			Width:                int16(width), | ||||||
|  | 			Height:               int16(height), | ||||||
|  | 			FrameCount:           1, | ||||||
|  | 			Depth:                24, | ||||||
|  | 			ColorTableId:         -1, | ||||||
|  | 			Conf:                 &mp4io.HV1Conf{Data: codec.AVCDecoderConfRecordBytes()}, | ||||||
|  | 		} | ||||||
|  | 		self.trackAtom.Media.Handler = &mp4io.HandlerRefer{ | ||||||
|  | 			SubType: [4]byte{'v', 'i', 'd', 'e'}, | ||||||
|  | 			Name:    []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'G', 'G', 0, 0, 0}, | ||||||
|  | 		} | ||||||
|  | 		self.trackAtom.Media.Info.Video = &mp4io.VideoMediaInfo{ | ||||||
|  | 			Flags: 0x000001, | ||||||
|  | 		} | ||||||
|  | 		self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | ||||||
| 	} else if self.Type() == av.AAC { | 	} else if self.Type() == av.AAC { | ||||||
| 		codec := self.CodecData.(aacparser.CodecData) | 		codec := self.CodecData.(aacparser.CodecData) | ||||||
| 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | ||||||
| @@ -183,8 +208,7 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 			SampleRate:       float64(codec.SampleRate()), | 			SampleRate:       float64(codec.SampleRate()), | ||||||
| 			Unknowns:         []mp4io.Atom{self.buildEsds(codec.MPEG4AudioConfigBytes())}, | 			Unknowns:         []mp4io.Atom{self.buildEsds(codec.MPEG4AudioConfigBytes())}, | ||||||
| 		} | 		} | ||||||
| 		//log.Fatalln(codec.MPEG4AudioConfigBytes()) |  | ||||||
| 		//log.Fatalln(codec.SampleFormat().BytesPerSample()) |  | ||||||
| 		self.trackAtom.Header.Volume = 1 | 		self.trackAtom.Header.Volume = 1 | ||||||
| 		self.trackAtom.Header.AlternateGroup = 1 | 		self.trackAtom.Header.AlternateGroup = 1 | ||||||
| 		self.trackAtom.Header.Duration = 0 | 		self.trackAtom.Header.Duration = 0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin