mkv in progress

This commit is contained in:
deepch 2022-01-27 04:10:06 +03:00
parent e0fc50b09e
commit 13fad59f2c
9 changed files with 828 additions and 0 deletions

147
format/mkv/demuxer.go Normal file
View File

@ -0,0 +1,147 @@
package mkv
import (
"encoding/binary"
"errors"
"io"
"time"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/h264parser"
"github.com/deepch/vdk/format/mkv/mkvio"
)
type Demuxer struct {
r *mkvio.Document
pkts []av.Packet
sps []byte
pps []byte
streams []*Stream
ps uint32
stage int
fc int
ls time.Duration
}
func NewDemuxer(r io.Reader) *Demuxer {
return &Demuxer{
r: mkvio.InitDocument(r),
}
}
func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
if err = self.probe(); err != nil {
return
}
for _, stream := range self.streams {
streams = append(streams, stream.CodecData)
}
if len(streams) == 0 {
return nil, errors.New("streams not found")
}
return streams, err
}
func (self *Demuxer) probe() (err error) {
if self.stage == 0 {
var el *mkvio.Element
el, err = self.r.GetVideoCodec()
if err != nil {
return
}
if el.ElementRegister.ID == mkvio.ElementCodecPrivate.ID {
payload := el.Content[6:]
var reader int
for pos := 0; pos < len(payload); pos = reader {
lens := int(binary.BigEndian.Uint16(payload[reader:]))
reader += 2
nal := payload[reader : reader+lens]
naluType := nal[0] & 0x1f
switch naluType {
case h264parser.NALU_SPS:
self.sps = nal
case h264parser.NALU_PPS:
self.pps = nal
}
reader += lens
reader++
}
}
if len(self.sps) > 0 && len(self.pps) > 0 {
var codec av.CodecData
codec, err = h264parser.NewCodecDataFromSPSAndPPS(self.sps, self.pps)
if err != nil {
return
}
stream := &Stream{}
stream.idx = 0
stream.demuxer = self
stream.CodecData = codec
self.streams = append(self.streams, stream)
}
self.stage++
}
return
}
func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
var el mkvio.Element
for {
el, err = self.r.ParseElement()
if err != nil {
return
}
if el.Type == 6 && el.ElementRegister.ID == mkvio.ElementSimpleBlock.ID {
self.fc++
nals, _ := h264parser.SplitNALUs(el.Content[4:])
for _, nal := range nals {
naluType := nal[0] & 0x1f
if naluType == 5 {
l1 := int(binary.BigEndian.Uint16(el.Content[2:4]))
dur := time.Duration(uint32(l1)) * time.Millisecond
self.ls += time.Duration(uint32(l1)) * time.Millisecond
self.ps = 0
pkt = av.Packet{IsKeyFrame: true, Idx: 0, Duration: dur, Time: self.ls, Data: append(binSize(len(nal)), nal...)}
return
} else if naluType == 1 {
l1 := int(binary.BigEndian.Uint16(el.Content[1:3]))
dur := time.Duration(uint32(l1)-self.ps) * time.Millisecond
self.ls += time.Duration(uint32(l1)-self.ps) * time.Millisecond
self.ps = uint32(l1)
pkt = av.Packet{Idx: 0, Duration: dur, Time: self.ls, Data: append(binSize(len(nal)), nal...)}
return
}
}
}
}
return
}
func binSize(val int) []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(val))
return buf
}

29
format/mkv/handler.go Normal file
View File

@ -0,0 +1,29 @@
package mkv
import (
"io"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
)
var CodecTypes = []av.CodecType{av.H264, av.AAC}
func Handler(h *avutil.RegisterHandler) {
h.Ext = ".mkv"
h.Probe = func(b []byte) bool {
return b[0] == 0x47 && b[188] == 0x47
}
h.ReaderDemuxer = func(r io.Reader) av.Demuxer {
return NewDemuxer(r)
}
h.WriterMuxer = func(w io.Writer) av.Muxer {
//return NewMuxer(w)
return nil
}
h.CodecTypes = CodecTypes
}

29
format/mkv/mkvio/ebml.go Normal file
View File

@ -0,0 +1,29 @@
package mkvio
import (
"io"
)
// Document represents a WebM file
type Document struct {
r io.Reader
}
// ElementRegister contains the ID, type and name of the
// standard WebM/Matroska elements
type ElementRegister struct {
ID uint32
Type uint8
Name string
}
// Element is a Matroska/WebM/EBML element
type Element struct {
ElementRegister
Parent *Element
Level int32
Size uint64
Content []byte // Data contained in the element, nil if it is a master element
Bytes []byte // Whole binary representation of the element (nil if data is missing)
}

View File

@ -0,0 +1,359 @@
package mkvio
const (
ElementType uint8 = 0x0
ElementTypeUnknown uint8 = 0x0
ElementTypeMaster uint8 = 0x1
ElementTypeUint uint8 = 0x2
ElementTypeInt uint8 = 0x3
ElementTypeString uint8 = 0x4
ElementTypeUnicode uint8 = 0x5
ElementTypeBinary uint8 = 0x6
ElementTypeFloat uint8 = 0x7
ElementTypeDate uint8 = 0x8
)
var (
ElementUnknown = ElementRegister{0x0, ElementTypeUnknown, "Unknown"}
ElementEBML = ElementRegister{0x1a45dfa3, ElementTypeMaster, "EBML"}
ElementEBMLVersion = ElementRegister{0x4286, ElementTypeUint, "EBMLVersion"}
ElementEBMLReadVersion = ElementRegister{0x42f7, ElementTypeUint, "EBMLReadVersion"}
ElementEBMLMaxIDLength = ElementRegister{0x42f2, ElementTypeUint, "EBMLMaxIDLength"}
ElementEBMLMaxSizeLength = ElementRegister{0x42f3, ElementTypeUint, "EBMLMaxSizeLength"}
ElementDocType = ElementRegister{0x4282, ElementTypeString, "DocType"}
ElementDocTypeVersion = ElementRegister{0x4287, ElementTypeUint, "DocTypeVersion"}
ElementDocTypeReadVersion = ElementRegister{0x4285, ElementTypeUint, "DocTypeReadVersion"}
ElementVoid = ElementRegister{0xec, ElementTypeBinary, "Void"}
ElementCRC32 = ElementRegister{0xbf, ElementTypeBinary, "CRC-32"}
ElementSegment = ElementRegister{0x18538067, ElementTypeMaster, "Segment"}
ElementSeekHead = ElementRegister{0x114d9b74, ElementTypeMaster, "SeekHead"}
ElementSeek = ElementRegister{0x4dbb, ElementTypeMaster, "Seek"}
ElementSeekID = ElementRegister{0x53ab, ElementTypeBinary, "SeekID"}
ElementSeekPosition = ElementRegister{0x53ac, ElementTypeUint, "SeekPosition"}
ElementInfo = ElementRegister{0x1549a966, ElementTypeMaster, "Info"}
ElementSegmentUID = ElementRegister{0x73a4, ElementTypeBinary, "SegmentUID"}
ElementSegmentFilename = ElementRegister{0x7384, ElementTypeUnicode, "SegmentFilename"}
ElementPrevUID = ElementRegister{0x3cb923, ElementTypeBinary, "PrevUID"}
ElementPrevFilename = ElementRegister{0x3c83ab, ElementTypeUnicode, "PrevFilename"}
ElementNextUID = ElementRegister{0x3eb923, ElementTypeBinary, "NextUID"}
ElementNextFilename = ElementRegister{0x3e83bb, ElementTypeUnicode, "NextFilename"}
ElementSegmentFamily = ElementRegister{0x4444, ElementTypeBinary, "SegmentFamily"}
ElementChapterTranslate = ElementRegister{0x6924, ElementTypeMaster, "ChapterTranslate"}
ElementChapterTranslateEditionUID = ElementRegister{0x69fc, ElementTypeUint, "ChapterTranslateEditionUID"}
ElementChapterTranslateCodec = ElementRegister{0x69bf, ElementTypeUint, "ChapterTranslateCodec"}
ElementChapterTranslateID = ElementRegister{0x69a5, ElementTypeBinary, "ChapterTranslateID"}
ElementTimecodeScale = ElementRegister{0x2ad7b1, ElementTypeUint, "TimecodeScale"}
ElementDuration = ElementRegister{0x4489, ElementTypeFloat, "Duration"}
ElementDateUTC = ElementRegister{0x4461, ElementTypeDate, "DateUTC"}
ElementTitle = ElementRegister{0x7ba9, ElementTypeUnicode, "Title"}
ElementMuxingApp = ElementRegister{0x4d80, ElementTypeUnicode, "MuxingApp"}
ElementWritingApp = ElementRegister{0x5741, ElementTypeUnicode, "WritingApp"}
ElementCluster = ElementRegister{0x1f43b675, ElementTypeMaster, "Cluster"}
ElementTimecode = ElementRegister{0xe7, ElementTypeUint, "Timecode"}
ElementSlientTracks = ElementRegister{0x5854, ElementTypeMaster, "SlientTracks"}
ElementSlientTrackNumber = ElementRegister{0x58d7, ElementTypeUint, "SlientTrackNumber"}
ElementPosition = ElementRegister{0xa7, ElementTypeUint, "Position"}
ElementPrevSize = ElementRegister{0xab, ElementTypeUint, "PrevSize"}
ElementSimpleBlock = ElementRegister{0xa3, ElementTypeBinary, "SimpleBlock"}
ElementBlockGroup = ElementRegister{0xa0, ElementTypeMaster, "BlockGroup"}
ElementBlock = ElementRegister{0xa1, ElementTypeBinary, "Block"}
ElementBlockAdditions = ElementRegister{0x75a1, ElementTypeMaster, "BlockAdditions"}
ElementBlockMore = ElementRegister{0xa6, ElementTypeMaster, "BlockMore"}
ElementBlockAddID = ElementRegister{0xee, ElementTypeUint, "BlockAddID"}
ElementBlockAdditional = ElementRegister{0xa5, ElementTypeBinary, "BlockAdditional"}
ElementBlockDuration = ElementRegister{0x9b, ElementTypeUint, "BlockDuration"}
ElementReferencePriority = ElementRegister{0xfa, ElementTypeUint, "ReferencePriority"}
ElementReferenceBlock = ElementRegister{0xfb, ElementTypeInt, "ReferenceBlock"}
ElementCodecState = ElementRegister{0xa4, ElementTypeBinary, "CodecState"}
ElementDiscardPadding = ElementRegister{0x75a2, ElementTypeInt, "DiscardPadding"}
ElementSlices = ElementRegister{0x8e, ElementTypeMaster, "Slices"}
ElementTimeSlice = ElementRegister{0xe8, ElementTypeMaster, "TimeSlice"}
ElementLaceNumber = ElementRegister{0xcc, ElementTypeUint, "LaceNumber"}
ElementTracks = ElementRegister{0x1654ae6b, ElementTypeMaster, "Tracks"}
ElementTrackEntry = ElementRegister{0xae, ElementTypeMaster, "TrackEntry"}
ElementTrackNumber = ElementRegister{0xd7, ElementTypeUint, "TrackNumber"}
ElementTrackUID = ElementRegister{0x73c5, ElementTypeUint, "TrackUID"}
ElementTrackType = ElementRegister{0x83, ElementTypeUint, "TrackType"}
ElementFlagEnabled = ElementRegister{0xb9, ElementTypeUint, "FlagEnabled"}
ElementFlagDefault = ElementRegister{0x88, ElementTypeUint, "FlagDefault"}
ElementFlagForced = ElementRegister{0x55aa, ElementTypeUint, "FlagForced"}
ElementFlagLacing = ElementRegister{0x9c, ElementTypeUint, "FlagLacing"}
ElementMinCache = ElementRegister{0x6de7, ElementTypeUint, "MinCache"}
ElementMaxCache = ElementRegister{0x6df8, ElementTypeUint, "MaxCache"}
ElementDefaultDuration = ElementRegister{0x23e383, ElementTypeUint, "DefaultDuration"}
ElementDefaultDecodedFieldDuration = ElementRegister{0x234e7a, ElementTypeUint, "DefaultDecodedFieldDuration"}
ElementMaxBlockAdditionID = ElementRegister{0x55ee, ElementTypeUint, "MaxBlockAdditionID"}
ElementName = ElementRegister{0x536e, ElementTypeUnicode, "Name"}
ElementLanguage = ElementRegister{0x22b59c, ElementTypeString, "Language"}
ElementCodecID = ElementRegister{0x86, ElementTypeString, "CodecID"}
ElementCodecPrivate = ElementRegister{0x63a2, ElementTypeBinary, "CodecPrivate"}
ElementCodecName = ElementRegister{0x258688, ElementTypeUnicode, "CodecName"}
ElementAttachmentLink = ElementRegister{0x7446, ElementTypeUint, "AttachmentLink"}
ElementCodecDecodeAll = ElementRegister{0xaa, ElementTypeUint, "CodecDecodeAll"}
ElementTrackOverlay = ElementRegister{0x6fab, ElementTypeUint, "TrackOverlay"}
ElementCodecDelay = ElementRegister{0x56aa, ElementTypeUint, "CodecDelay"}
ElementSeekPreRoll = ElementRegister{0x56bb, ElementTypeUint, "SeekPreRoll"}
ElementTrackTranslate = ElementRegister{0x6624, ElementTypeMaster, "TrackTranslate"}
ElementTrackTranslateEditionUID = ElementRegister{0x66fc, ElementTypeUint, "TrackTranslateEditionUID"}
ElementTrackTranslateCodec = ElementRegister{0x66bf, ElementTypeUint, "TrackTranslateCodec"}
ElementTrackTranslateTrackID = ElementRegister{0x66a5, ElementTypeBinary, "TrackTranslateTrackID"}
ElementVideo = ElementRegister{0xe0, ElementTypeMaster, "Video"}
ElementFlagInterlaced = ElementRegister{0x9a, ElementTypeUint, "FlagInterlaced"}
ElementStereoMode = ElementRegister{0x53b8, ElementTypeUint, "StereoMode"}
ElementAlphaMode = ElementRegister{0x53c0, ElementTypeUint, "AlphaMode"}
ElementPixelWidth = ElementRegister{0xb0, ElementTypeUint, "PixelWidth"}
ElementPixelHeight = ElementRegister{0xba, ElementTypeUint, "PixelHeight"}
ElementPixelCropBottom = ElementRegister{0x54aa, ElementTypeUint, "PixelCropBottom"}
ElementPixelCropTop = ElementRegister{0x54bb, ElementTypeUint, "PixelCropTop"}
ElementPixelCropLeft = ElementRegister{0x54cc, ElementTypeUint, "PixelCropLeft"}
ElementPixelCropRight = ElementRegister{0x54dd, ElementTypeUint, "PixelCropRight"}
ElementDisplayWidth = ElementRegister{0x54b0, ElementTypeUint, "DisplayWidth"}
ElementDisplayHeight = ElementRegister{0x54ba, ElementTypeUint, "DisplayHeight"}
ElementDisplayUint = ElementRegister{0x54b2, ElementTypeUint, "DisplayUint"}
ElementAspectRatioType = ElementRegister{0x54b3, ElementTypeUint, "AspectRatioType"}
ElementColourSpace = ElementRegister{0x2eb524, ElementTypeBinary, "ColourSpace"}
ElementAudio = ElementRegister{0xe1, ElementTypeMaster, "Audio"}
ElementSamplingFrequency = ElementRegister{0xb5, ElementTypeFloat, "SamplingFrequency"}
ElementOutputSamplingFrequency = ElementRegister{0x78b5, ElementTypeFloat, "OutputSamplingFrequency"}
ElementChannels = ElementRegister{0x9f, ElementTypeUint, "Channels"}
ElementBitDepth = ElementRegister{0x6264, ElementTypeUint, "BitDepth"}
ElementTrackOperation = ElementRegister{0xe2, ElementTypeMaster, "TrackOperation"}
ElementTrackCombinePlanes = ElementRegister{0xe3, ElementTypeMaster, "TrackCombinePlanes"}
ElementTrackPlane = ElementRegister{0xe4, ElementTypeMaster, "TrackPlane"}
ElementTrackPlaneUID = ElementRegister{0xe5, ElementTypeUint, "TrackPlaneUID"}
ElementTrackPlaneType = ElementRegister{0xe6, ElementTypeUint, "TrackPlaneType"}
ElementTrackJoinBlocks = ElementRegister{0xe9, ElementTypeMaster, "TrackJoinBlocks"}
ElementTrackJoinUID = ElementRegister{0xed, ElementTypeUint, "TrackJoinUID"}
ElementContentEncodings = ElementRegister{0x6d80, ElementTypeMaster, "ContentEncodings"}
ElementContentEncoding = ElementRegister{0x6240, ElementTypeMaster, "ContentEncoding"}
ElementContentEncodingOrder = ElementRegister{0x5031, ElementTypeUint, "ContentEncodingOrder"}
ElementContentEncodingScope = ElementRegister{0x5032, ElementTypeUint, "ContentEncodingScope"}
ElementContentEncodingType = ElementRegister{0x5033, ElementTypeUint, "ContentEncodingType"}
ElementContentCompression = ElementRegister{0x5034, ElementTypeMaster, "ContentCompression"}
ElementContentCompAlgo = ElementRegister{0x4254, ElementTypeUint, "ContentCompAlgo"}
ElementContentCompSettings = ElementRegister{0x4255, ElementTypeBinary, "ContentCompSettings"}
ElementContentEncryption = ElementRegister{0x5035, ElementTypeMaster, "ContentEncryption"}
ElementContentEncAlgo = ElementRegister{0x47e1, ElementTypeUint, "ContentEncAlgo"}
ElementContentEncKeyID = ElementRegister{0x47e2, ElementTypeUint, "ContentEncKeyID"}
ElementContentSignature = ElementRegister{0x47e3, ElementTypeBinary, "ContentSignature"}
ElementContentSigKeyID = ElementRegister{0x47e4, ElementTypeBinary, "ContentSigKeyID"}
ElementContentSigAlgo = ElementRegister{0x47e5, ElementTypeUint, "ContentSigAlgo"}
ElementContentSigHashAlgo = ElementRegister{0x47e6, ElementTypeUint, "ContentSigHashAlgo"}
ElementCues = ElementRegister{0x1c53bb6b, ElementTypeMaster, "Cues"}
ElementCuePoint = ElementRegister{0xbb, ElementTypeMaster, "CuePoint"}
ElementCueTime = ElementRegister{0xb3, ElementTypeUint, "CueTime"}
ElementCueTrackPositions = ElementRegister{0xb7, ElementTypeMaster, "CueTrackPositions"}
ElementCueTrack = ElementRegister{0xf7, ElementTypeUint, "CueTrack"}
ElementCueClusterPosition = ElementRegister{0xf1, ElementTypeUint, "CueClusterPosition"}
ElementCueRelativePosition = ElementRegister{0xf0, ElementTypeUint, "CueRelativePosition"}
ElementCueDuration = ElementRegister{0xb2, ElementTypeUint, "CueDuration"}
ElementCueBlockNumber = ElementRegister{0x5378, ElementTypeUint, "CueBlockNumber"}
ElementCueCodecState = ElementRegister{0xea, ElementTypeUint, "CueCodecState"}
ElementCueReference = ElementRegister{0xdb, ElementTypeMaster, "CueReference"}
ElementCueRefTime = ElementRegister{0x96, ElementTypeUint, "CueRefTime"}
ElementAttachments = ElementRegister{0x1941a469, ElementTypeMaster, "Attachments"}
ElementAttachedFile = ElementRegister{0x61a7, ElementTypeMaster, "AttachedFile"}
ElementFileDescription = ElementRegister{0x467e, ElementTypeUnicode, "FileDescription"}
ElementFileName = ElementRegister{0x466e, ElementTypeUnicode, "FileName"}
ElementFileMimeType = ElementRegister{0x6460, ElementTypeString, "FileMimeType"}
ElementFileData = ElementRegister{0x465c, ElementTypeBinary, "FileData"}
ElementFileUID = ElementRegister{0x46ae, ElementTypeUint, "FileUID"}
ElementChapters = ElementRegister{0x1043a770, ElementTypeMaster, "Chapters"}
ElementEditionEntry = ElementRegister{0x45b9, ElementTypeMaster, "EditionEntry"}
ElementEditionUID = ElementRegister{0x45bc, ElementTypeUint, "EditionUID"}
ElementEditionFlagHidden = ElementRegister{0x45bd, ElementTypeUint, "EditionFlagHidden"}
ElementEditionFlagDefault = ElementRegister{0x45db, ElementTypeUint, "EditionFlagDefault"}
ElementEditionFlagOrdered = ElementRegister{0x45dd, ElementTypeUint, "EditionFlagOrdered"}
ElementChapterAtom = ElementRegister{0xb6, ElementTypeMaster, "ChapterAtom"}
ElementChapterUID = ElementRegister{0x73c4, ElementTypeUint, "ChapterUID"}
ElementChapterStringUID = ElementRegister{0x5654, ElementTypeUnicode, "ChapterStringUID"}
ElementChapterTimeStart = ElementRegister{0x91, ElementTypeUint, "ChapterTimeStart"}
ElementChapterTimeEnd = ElementRegister{0x92, ElementTypeUint, "ChapterTimeEnd"}
ElementChapterFlagHidden = ElementRegister{0x98, ElementTypeUint, "ChapterFlagHidden"}
ElementChapterFlagEnabled = ElementRegister{0x4598, ElementTypeUint, "ChapterFlagEnabled"}
ElementChapterSegmentUID = ElementRegister{0x6e67, ElementTypeBinary, "ChapterSegmentUID"}
ElementChapterSegmentEditionUID = ElementRegister{0x6ebc, ElementTypeUint, "ChapterSegmentEditionUID"}
ElementChapterPhysicalEquiv = ElementRegister{0x63c3, ElementTypeUint, "ChapterPhysicalEquiv"}
ElementChapterTrack = ElementRegister{0x8f, ElementTypeMaster, "ChapterTrack"}
ElementChapterTrackNumber = ElementRegister{0x89, ElementTypeUint, "ChapterTrackNumber"}
ElementChapterDisplay = ElementRegister{0x80, ElementTypeMaster, "ChapterDisplay"}
ElementChapString = ElementRegister{0x85, ElementTypeUnicode, "ChapString"}
ElementChapLanguage = ElementRegister{0x437c, ElementTypeString, "ChapLanguage"}
ElementChapCountry = ElementRegister{0x437e, ElementTypeString, "ChapCountry"}
ElementChapProcess = ElementRegister{0x6944, ElementTypeMaster, "ChapProcess"}
ElementChapProcessCodecID = ElementRegister{0x6955, ElementTypeUint, "ChapProcessCodecID"}
ElementChapProcessPrivate = ElementRegister{0x450d, ElementTypeBinary, "ChapProcessPrivate"}
ElementChapProcessCommand = ElementRegister{0x6911, ElementTypeMaster, "ChapProcessCommand"}
ElementChapProcessTime = ElementRegister{0x6922, ElementTypeUint, "ChapProcessTime"}
ElementChapProcessData = ElementRegister{0x6933, ElementTypeBinary, "ChapProcessData"}
// TODO: Add tags
)
// GetElementRegister returns the infos concerning the provided element ID
func GetElementRegister(id uint32) ElementRegister {
switch id {
case ElementEBML.ID:
return ElementEBML
case ElementEBMLVersion.ID:
return ElementEBMLVersion
case ElementEBMLReadVersion.ID:
return ElementEBMLReadVersion
case ElementEBMLMaxIDLength.ID:
return ElementEBMLMaxIDLength
case ElementEBMLMaxSizeLength.ID:
return ElementEBMLMaxSizeLength
case ElementDocType.ID:
return ElementDocType
case ElementDocTypeVersion.ID:
return ElementDocTypeVersion
case ElementDocTypeReadVersion.ID:
return ElementDocTypeReadVersion
case ElementVoid.ID:
return ElementVoid
case ElementCRC32.ID:
return ElementCRC32
case ElementSegment.ID:
return ElementSegment
case ElementSeekHead.ID:
return ElementSeekHead
case ElementSeek.ID:
return ElementSeek
case ElementSeekID.ID:
return ElementSeekID
case ElementSeekPosition.ID:
return ElementSeekPosition
case ElementInfo.ID:
return ElementInfo
case ElementTimecodeScale.ID:
return ElementTimecodeScale
case ElementDuration.ID:
return ElementDuration
case ElementDateUTC.ID:
return ElementDateUTC
case ElementTitle.ID:
return ElementTitle
case ElementMuxingApp.ID:
return ElementMuxingApp
case ElementWritingApp.ID:
return ElementWritingApp
case ElementCluster.ID:
return ElementCluster
case ElementTimecode.ID:
return ElementTimecode
case ElementPrevSize.ID:
return ElementPrevSize
case ElementSimpleBlock.ID:
return ElementSimpleBlock
case ElementBlockGroup.ID:
return ElementBlockGroup
case ElementBlock.ID:
return ElementBlock
case ElementBlockAdditions.ID:
return ElementBlockAdditions
case ElementBlockMore.ID:
return ElementBlockMore
case ElementBlockAddID.ID:
return ElementBlockAddID
case ElementBlockAdditional.ID:
return ElementBlockAdditional
case ElementBlockDuration.ID:
return ElementBlockDuration
case ElementReferenceBlock.ID:
return ElementReferenceBlock
case ElementDiscardPadding.ID:
return ElementDiscardPadding
case ElementTracks.ID:
return ElementTracks
case ElementTrackEntry.ID:
return ElementTrackEntry
case ElementTrackNumber.ID:
return ElementTrackNumber
case ElementTrackUID.ID:
return ElementTrackUID
case ElementTrackType.ID:
return ElementTrackType
case ElementFlagEnabled.ID:
return ElementFlagEnabled
case ElementFlagDefault.ID:
return ElementFlagDefault
case ElementFlagForced.ID:
return ElementFlagForced
case ElementFlagLacing.ID:
return ElementFlagLacing
case ElementDefaultDuration.ID:
return ElementDefaultDuration
case ElementName.ID:
return ElementName
case ElementLanguage.ID:
return ElementLanguage
case ElementCodecID.ID:
return ElementCodecID
case ElementCodecPrivate.ID:
return ElementCodecPrivate
case ElementCodecName.ID:
return ElementCodecName
case ElementCodecDelay.ID:
return ElementCodecDelay
case ElementSeekPreRoll.ID:
return ElementSeekPreRoll
case ElementVideo.ID:
return ElementVideo
case ElementFlagInterlaced.ID:
return ElementFlagInterlaced
case ElementStereoMode.ID:
return ElementStereoMode
case ElementAlphaMode.ID:
return ElementAlphaMode
case ElementPixelWidth.ID:
return ElementPixelWidth
case ElementPixelHeight.ID:
return ElementPixelHeight
case ElementPixelCropBottom.ID:
return ElementPixelCropBottom
case ElementPixelCropTop.ID:
return ElementPixelCropTop
case ElementPixelCropLeft.ID:
return ElementPixelCropLeft
case ElementPixelCropRight.ID:
return ElementPixelCropRight
case ElementDisplayWidth.ID:
return ElementDisplayWidth
case ElementDisplayHeight.ID:
return ElementDisplayHeight
case ElementDisplayUint.ID:
return ElementDisplayUint
case ElementAspectRatioType.ID:
return ElementAspectRatioType
case ElementAudio.ID:
return ElementAudio
case ElementSamplingFrequency.ID:
return ElementSamplingFrequency
case ElementOutputSamplingFrequency.ID:
return ElementOutputSamplingFrequency
case ElementChannels.ID:
return ElementChannels
case ElementBitDepth.ID:
return ElementBitDepth
case ElementContentEncodings.ID:
return ElementContentEncodings
case ElementContentEncoding.ID:
return ElementContentEncoding
case ElementContentEncodingOrder.ID:
return ElementContentEncodingOrder
case ElementContentEncodingScope.ID:
return ElementContentEncodingScope
case ElementContentEncodingType.ID:
return ElementContentEncodingType
case ElementContentEncryption.ID:
return ElementContentEncryption
case ElementContentEncAlgo.ID:
return ElementContentEncAlgo
case ElementContentEncKeyID.ID:
return ElementContentEncKeyID
case ElementUnknown.ID:
return ElementUnknown
default:
return ElementUnknown
}
}

214
format/mkv/mkvio/parser.go Normal file
View File

@ -0,0 +1,214 @@
package mkvio
import (
"errors"
"io"
)
var (
ErrParse = errors.New("Parse error")
ErrUnexpectedEOF = errors.New("Unexpected EOF")
)
// InitDocument creates a MKV/WebM document containing the file data
// It does not do any parsing
func InitDocument(r io.Reader) *Document {
doc := new(Document)
doc.r = r
return doc
}
// ParseAll parses the entire MKV/WebM document
// When an EBML/WebM element is encountered, it calls the provided function
// and passes the newly parsed element
func (doc *Document) ParseAll(c func(Element)) error {
for {
el, err := doc.ParseElement()
if err != nil {
return err
}
c(el)
}
return nil
}
func (doc *Document) GetVideoCodec() (*Element, error) {
for {
el, err := doc.ParseElement()
if err != nil {
return nil, err
}
if el.ElementRegister.ID == ElementCodecPrivate.ID {
return &el, nil
}
}
return nil, errors.New("not found")
}
// ParseElement parses an EBML element starting at the document's current cursor position.
// Because of its nature, it does not set the elements's parent or level.
func (doc *Document) ParseElement() (Element, error) {
var el Element
id, err := doc.GetElementID(&el)
if err != nil {
return el, err
}
size, err := doc.GetElementSize(&el)
if err != nil {
return el, err
}
reg := GetElementRegister(id)
el.ID = reg.ID
el.Type = reg.Type
el.Name = reg.Name
el.Size = size
if el.Type != ElementTypeMaster {
d, err := doc.GetElementContent(&el)
if err != nil {
return el, err
}
el.Content = d
}
return el, nil
}
// GetElementID tries to parse the next element's id,
// starting from the document's current cursor position.
func (doc *Document) GetElementID(el *Element) (uint32, error) {
b := make([]byte, 1)
_, err := io.ReadFull(doc.r, b)
if err != nil {
return 0, err
}
if ((b[0] & 0x80) >> 7) == 1 { // Class A ID (on 1 byte)
el.Bytes = append(el.Bytes, b[0])
return uint32(b[0]), nil
}
if ((b[0] & 0x40) >> 6) == 1 { // Class B ID (on 2 byte)
bb := make([]byte, 2)
copy(bb, b)
_, err = io.ReadFull(doc.r, bb[1:])
if err != nil {
return 0, err
}
el.Bytes = append(el.Bytes, bb...)
return uint32(pack(2, bb)), nil
}
if ((b[0] & 0x20) >> 5) == 1 { // Class C ID (on 3 bytes)
bb := make([]byte, 3)
copy(bb, b)
_, err = io.ReadFull(doc.r, bb[1:])
if err != nil {
return 0, err
}
el.Bytes = append(el.Bytes, bb...)
return uint32(pack(3, bb)), nil
}
if ((b[0] & 0x10) >> 4) == 1 { // Class D ID (on 4 bytes)
bb := make([]byte, 4)
copy(bb, b)
_, err = io.ReadFull(doc.r, bb[1:])
if err != nil {
return 0, err
}
el.Bytes = append(el.Bytes, bb...)
return uint32(pack(4, bb)), nil
}
return 0, ErrParse
}
// GetElementSize tries to parse the next element's size,
// starting from the document's current cursor position.
func (doc *Document) GetElementSize(el *Element) (uint64, error) {
b := make([]byte, 1)
_, err := io.ReadFull(doc.r, b)
if err != nil {
return 0, err
}
var mask byte
var length uint64
if b[0] >= 0x80 {
length = 1
mask = 0x7f
} else if b[0] >= 0x40 {
length = 2
mask = 0x3f
} else if b[0] >= 0x20 {
length = 3
mask = 0x1f
} else if b[0] >= 0x10 {
length = 4
mask = 0x0f
} else if b[0] >= 0x08 {
length = 5
mask = 0x07
} else if b[0] >= 0x04 {
length = 6
mask = 0x03
} else if b[0] >= 0x02 {
length = 7
mask = 0x01
} else if b[0] >= 0x01 {
length = 8
mask = 0x00
} else {
return 0, ErrParse
}
bb := make([]byte, length)
bb[0] = b[0]
if length > 1 {
_, err = io.ReadFull(doc.r, bb[1:])
if err != nil {
return 0, err
}
}
el.Bytes = append(el.Bytes, bb...)
bb[0] &= mask
v := pack(int(length), bb)
return v, nil
}
// GetElementContent returns the element's data (if any)
// Data is present if the element's type is not Master
func (doc *Document) GetElementContent(el *Element) ([]byte, error) {
buf := make([]byte, el.Size)
_, err := io.ReadFull(doc.r, buf)
if err != nil {
return nil, err
}
el.Bytes = append(el.Bytes, buf...)
return buf, nil
}

23
format/mkv/mkvio/utils.go Normal file
View File

@ -0,0 +1,23 @@
package mkvio
func pack(n int, b []byte) uint64 {
var v uint64
var k uint64 = (uint64(n) - 1) * 8
for i := 0; i < n; i++ {
v |= uint64(b[i]) << k
k -= 8
}
return v
}
func unpack(n int, v uint64) []byte {
var b []byte
for i := uint(n); i > 0; i-- {
b = append(b, byte(v>>(8*i))&0xff)
}
return b
}

24
format/mkv/stream.go Normal file
View File

@ -0,0 +1,24 @@
package mkv
import (
"time"
"github.com/deepch/vdk/av"
)
type Stream struct {
av.CodecData
demuxer *Demuxer
pid uint16
streamId uint8
streamType uint8
idx int
iskeyframe bool
pts, dts time.Duration
data []byte
datalen int
}

1
go.mod
View File

@ -6,4 +6,5 @@ require (
github.com/pion/interceptor v0.1.6
github.com/pion/webrtc/v2 v2.2.26
github.com/pion/webrtc/v3 v3.1.17
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c // indirect
)

2
go.sum
View File

@ -154,6 +154,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c h1:Nu1I2o5Lk5nvn2RChPOJ1MzTXKZoHiy665a5aANHssQ=
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c/go.mod h1:Mtv+LuzkLR5r7fwBlvqI/N/5d4nOaH/7fpgQFXwxnFk=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=