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/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
									
									
									
									
									
								
							
							
						
						
									
										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/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= | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 deepch
					deepch