mkv in progress
This commit is contained in:
		
							
								
								
									
										147
									
								
								format/mkv/demuxer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								format/mkv/demuxer.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										29
									
								
								format/mkv/handler.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										29
									
								
								format/mkv/mkvio/ebml.go
									
									
									
									
									
										Normal 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) | ||||||
|  | } | ||||||
							
								
								
									
										359
									
								
								format/mkv/mkvio/elements.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								format/mkv/mkvio/elements.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										214
									
								
								format/mkv/mkvio/parser.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										23
									
								
								format/mkv/mkvio/utils.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										24
									
								
								format/mkv/stream.go
									
									
									
									
									
										Normal 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
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,4 +6,5 @@ require ( | |||||||
| 	github.com/pion/interceptor v0.1.6 | 	github.com/pion/interceptor v0.1.6 | ||||||
| 	github.com/pion/webrtc/v2 v2.2.26 | 	github.com/pion/webrtc/v2 v2.2.26 | ||||||
| 	github.com/pion/webrtc/v3 v3.1.17 | 	github.com/pion/webrtc/v3 v3.1.17 | ||||||
|  | 	github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c // indirect | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | 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/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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 deepch
					deepch