work HEVC in progress
This commit is contained in:
parent
a102e9cb3e
commit
d9a713ebc1
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user