ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
module.audio-video.matroska.php
Go to the documentation of this file.
1 <?php
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
6 // also https://github.com/JamesHeinrich/getID3 //
8 // See readme.txt for more details //
10 // //
11 // module.audio-video.matriska.php //
12 // module for analyzing Matroska containers //
13 // dependencies: NONE //
14 // ///
16 
17 
18 define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation.
19 define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
20 define('EBML_ID_TAGS', 0x0254C367); // [12][54][C3][67] -- Element containing elements specific to Tracks/Chapters. A list of valid tags can be found <http://www.matroska.org/technical/specs/tagging/index.html>.
21 define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file.
22 define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described.
23 define('EBML_ID_SEGMENT', 0x08538067); // [18][53][80][67] -- This element contains all other top-level (level 1) elements. Typically a Matroska file is composed of 1 segment.
24 define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files.
25 define('EBML_ID_EBML', 0x0A45DFA3); // [1A][45][DF][A3] -- Set the EBML characteristics of the data to follow. Each EBML document has to start with this.
26 define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment.
27 define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure.
28 define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form.
29 define('EBML_ID_TRACKTIMECODESCALE', 0x03314F); // [23][31][4F] -- The scale to apply on this track to work at normal speed in relation with other tracks (mostly used to adjust video speed when the audio length differs).
30 define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame.
31 define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec.
32 define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used.
33 define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds).
34 define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits).
35 define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value.
36 define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used.
37 define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used.
38 define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment.
39 define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits).
40 define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment.
41 define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits).
42 define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are:
43 define('EBML_ID_CONTENTCOMPSETTINGS', 0x0255); // [42][55] -- Settings that might be needed by the decompressor. For Header Stripping (ContentCompAlgo=3), the bytes that were removed from the beggining of each frames of the track.
44 define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case).
45 define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file.
46 define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file.
47 define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file.
48 define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska).
49 define('EBML_ID_EBMLMAXSIZELENGTH', 0x02F3); // [42][F3] -- The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not override the element size indicated at the beginning of an element. Elements that have an indicated size which is larger than what is allowed by EBMLMaxSizeLength shall be considered invalid.
50 define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file.
51 define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form.
52 define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains.
53 define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits).
54 define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date.
55 define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form.
56 define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag.
57 define('EBML_ID_TAGBINARY', 0x0485); // [44][85] -- The values of the Tag if it is binary. Note that this cannot be used in the same SimpleTag as TagString.
58 define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag.
59 define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale).
60 define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent.
61 define('EBML_ID_CHAPTERFLAGENABLED', 0x0598); // [45][98] -- Specify wether the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the movie should skip all the content between the TimeStart and TimeEnd of this chapter.
62 define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored.
63 define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition.
64 define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition.
65 define('EBML_ID_EDITIONFLAGHIDDEN', 0x05BD); // [45][BD] -- If an edition is hidden (1), it should not be available to the user interface (but still to Control Tracks).
66 define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one.
67 define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced.
68 define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file.
69 define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file.
70 define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file.
71 define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed.
72 define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
73 define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
74 define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
75 define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
76 define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
77 define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
78 define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
79 define('EBML_ID_CONTENTSIGHASHALGO', 0x07E6); // [47][E6] -- The hash algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
80 define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3").
81 define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element.
82 define('EBML_ID_CONTENTENCODINGORDER', 0x1031); // [50][31] -- Tells when this modification was used during encoding/muxing starting with 0 and counting upwards. The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to be unique over all ContentEncodingOrder elements in the segment.
83 define('EBML_ID_CONTENTENCODINGSCOPE', 0x1032); // [50][32] -- A bit field that describes which elements have been modified in this way. Values (big endian) can be OR'ed. Possible values:
84 define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values:
85 define('EBML_ID_CONTENTCOMPRESSION', 0x1034); // [50][34] -- Settings describing the compression used. Must be present if the value of ContentEncodingType is 0 and absent otherwise. Each block must be decompressable even if no previous block is available in order not to prevent seeking.
86 define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise.
87 define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster.
88 define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name.
89 define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster.
90 define('EBML_ID_TRACKOFFSET', 0x137F); // [53][7F] -- A value to add to the Block's Timecode. This can be used to adjust the playback offset of a track.
91 define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name.
92 define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element).
93 define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode.
94 define('EBML_ID_OLDSTEREOMODE', 0x13B9); // [53][B9] -- Bogus StereoMode value used in old versions of libmatroska. DO NOT USE. (0: mono, 1: right eye, 2: left eye, 3: both eyes).
95 define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content).
96 define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display.
97 define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches).
98 define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed).
99 define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display.
100 define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image.
101 define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image.
102 define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image.
103 define('EBML_ID_FLAGFORCED', 0x15AA); // [55][AA] -- Set if that track MUST be used during playback. There can be many forced track for a kind (audio, video or subs), the player should select the one which language matches the user preference or the default + forced track. Overlay MAY happen between a forced and non-forced track of the same kind.
104 define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track.
105 define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3").
106 define('EBML_ID_CLUSTERSILENTTRACKS', 0x1854); // [58][54] -- The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks on seeking. Then you should decide what track to use.
107 define('EBML_ID_CLUSTERSILENTTRACKNUMBER', 0x18D7); // [58][D7] -- One of the track number that are not used from now on in the stream. It could change later if not specified as silent in a further Cluster.
108 define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file.
109 define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption.
110 define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM.
111 define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec.
112 define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment.
113 define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values.
114 define('EBML_ID_TAGCHAPTERUID', 0x23C4); // [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment.
115 define('EBML_ID_TAGTRACKUID', 0x23C5); // [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment.
116 define('EBML_ID_TAGATTACHMENTUID', 0x23C6); // [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment.
117 define('EBML_ID_TAGEDITIONUID', 0x23C9); // [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment.
118 define('EBML_ID_TARGETTYPE', 0x23CA); // [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType).
119 define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec.
120 define('EBML_ID_TRACKTRANSLATETRACKID', 0x26A5); // [66][A5] -- The binary value used to represent this track in the chapter codec data. The format depends on the ChapProcessCodecID used.
121 define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
122 define('EBML_ID_TRACKTRANSLATEEDITIONUID', 0x26FC); // [66][FC] -- Specify an edition UID on which this translation applies. When not specified, it means for all editions found in the segment.
123 define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target.
124 define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType).
125 define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom.
126 define('EBML_ID_CHAPPROCESSTIME', 0x2922); // [69][22] -- Defines when the process command should be handled (0: during the whole chapter, 1: before starting playback, 2: after playback of the chapter).
127 define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment.
128 define('EBML_ID_CHAPPROCESSDATA', 0x2933); // [69][33] -- Contains the command information. The data should be interpreted depending on the ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post commands.
129 define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom.
130 define('EBML_ID_CHAPPROCESSCODECID', 0x2955); // [69][55] -- Contains the type of the codec used for the processing. A value of 0 means native Matroska processing (to be defined), a value of 1 means the DVD command set is used. More codec IDs can be added later.
131 define('EBML_ID_CHAPTERTRANSLATEID', 0x29A5); // [69][A5] -- The binary value used to represent this segment in the chapter codec data. The format depends on the ChapProcessCodecID used.
132 define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
133 define('EBML_ID_CHAPTERTRANSLATEEDITIONUID', 0x29FC); // [69][FC] -- Specify an edition UID on which this correspondance applies. When not specified, it means for all editions found in the segment.
134 define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption.
135 define('EBML_ID_MINCACHE', 0x2DE7); // [6D][E7] -- The minimum number of frames a player should be able to cache during playback. If set to 0, the reference pseudo-cache system is not used.
136 define('EBML_ID_MAXCACHE', 0x2DF8); // [6D][F8] -- The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed.
137 define('EBML_ID_CHAPTERSEGMENTUID', 0x2E67); // [6E][67] -- A segment to play in place of this chapter. Edition ChapterSegmentEditionUID should be used for this segment, otherwise no edition is used.
138 define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID.
139 define('EBML_ID_TRACKOVERLAY', 0x2FAB); // [6F][AB] -- Specify that this track is an overlay track for the Track specified (in the u-integer). That means when this track has a gap (see SilentTracks) the overlay track should be used instead. The order of multiple TrackOverlay matters, the first one is the one that should be used. If not found it should be the second, etc.
140 define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters.
141 define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment.
142 define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits).
143 define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter.
144 define('EBML_ID_TRACKUID', 0x33C5); // [73][C5] -- A unique ID to identify the Track. This should be kept the same when making a direct stream copy of the Track to another file.
145 define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec.
146 define('EBML_ID_CLUSTERBLOCKADDITIONS', 0x35A1); // [75][A1] -- Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block structure could still see and use/skip these data.
147 define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix.
148 define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques).
149 define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment.
150 define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display.
151 define('EBML_ID_TRACKTYPE', 0x03); // [83] -- A set of track types coded on 8 bits (1: video, 2: audio, 3: complex, 0x10: logo, 0x11: subtitle, 0x12: buttons, 0x20: control).
152 define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom.
153 define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info.
154 define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference.
155 define('EBML_ID_CHAPTERTRACKNUMBER', 0x09); // [89] -- UID of the Track to apply this chapter too. In the absense of a control track, choosing this chapter will select the listed Tracks and deselect unlisted tracks. Absense of this element indicates that the Chapter should be applied to any currently used Tracks.
156 define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description.
157 define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply
158 define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled).
159 define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled).
160 define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block.
161 define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block.
162 define('EBML_ID_CHAPTERFLAGHIDDEN', 0x18); // [98] -- If a chapter is hidden (1), it should not be available to the user interface (but still to Control Tracks).
163 define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced.
164 define('EBML_ID_CLUSTERBLOCKDURATION', 0x1B); // [9B] -- The duration of the Block (based on TimecodeScale). This element is mandatory when DefaultDuration is set for the track. When not written and with no DefaultDuration, the value is assumed to be the difference between the timecode of this Block and the timecode of the next Block in "display" order (not coding order). This element can be useful at the end of a Track (as there is not other Block available), or when there is a break in a track like for subtitle tracks.
165 define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing.
166 define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track.
167 define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock.
168 define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode.
169 define('EBML_ID_CLUSTERBLOCKVIRTUAL', 0x22); // [A2] -- A Block with no data. It must be stored in the stream at the place the real Block should be in display order.
170 define('EBML_ID_CLUSTERSIMPLEBLOCK', 0x23); // [A3] -- Similar to Block but without all the extra information, mostly used to reduced overhead when no extra feature is needed.
171 define('EBML_ID_CLUSTERCODECSTATE', 0x24); // [A4] -- The new codec state to use. Data interpretation is private to the codec. This information should always be referenced by a seek entry.
172 define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID).
173 define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters.
174 define('EBML_ID_CLUSTERPOSITION', 0x27); // [A7] -- Position of the Cluster in the segment (0 in live broadcast streams). It might help to resynchronise offset on damaged streams.
175 define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data.
176 define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing.
177 define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements.
178 define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed).
179 define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels.
180 define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base.
181 define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz.
182 define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks).
183 define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode.
184 define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used.
185 define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels.
186 define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment.
187 define('EBML_ID_CRC32', 0x3F); // [BF] -- The CRC is computed on all the data of the Master element it's in, regardless of its position. It's recommended to put the CRC value at the beggining of the Master element for easier reading. All level 1 elements should include a CRC-32.
188 define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block).
189 define('EBML_ID_CLUSTERLACENUMBER', 0x4C); // [CC] -- The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
190 define('EBML_ID_CLUSTERFRAMENUMBER', 0x4D); // [CD] -- The number of the frame to generate from this lace with this delay (allow you to generate many frames from the same Block/Frame).
191 define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element.
192 define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element.
193 define('EBML_ID_TRACKNUMBER', 0x57); // [D7] -- The track number as used in the Block Header (using more than 127 tracks is not encouraged, though the design allows an unlimited number).
194 define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks.
195 define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings.
196 define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings.
197 define('EBML_ID_CLUSTERTIMESLICE', 0x68); // [E8] -- Contains extra time information about the data contained in the Block. While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
198 define('EBML_ID_CUECODECSTATE', 0x6A); // [EA] -- The position of the Codec State corresponding to this Cue element. 0 means that the data is taken from the initial Track Entry.
199 define('EBML_ID_CUEREFCODECSTATE', 0x6B); // [EB] -- The position of the Codec State corresponding to this referenced element. 0 means that the data is taken from the initial Track Entry.
200 define('EBML_ID_VOID', 0x6C); // [EC] -- Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is discarded. Also used to reserve space in a sub-element for later use.
201 define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale).
202 define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level.
203 define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block.
204 define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given.
205 define('EBML_ID_CLUSTERREFERENCEPRIORITY', 0x7A); // [FA] -- This frame is referenced and has the specified cache priority. In cache only a frame of the same or higher priority can replace this frame. A value of 0 means the frame is not referenced.
206 define('EBML_ID_CLUSTERREFERENCEBLOCK', 0x7B); // [FB] -- Timecode of another frame used as a reference (ie: B or P frame). The timecode is relative to the block it's attached to.
207 define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] -- Relative position of the data that should be in position of the virtual block.
208 
209 
217 {
218  // public options
219  public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
220  public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
221 
222  // private parser settings/placeholders
223  private $EBMLbuffer = '';
224  private $EBMLbuffer_offset = 0;
225  private $EBMLbuffer_length = 0;
226  private $current_offset = 0;
228 
229  public function Analyze()
230  {
231  $info = &$this->getid3->info;
232 
233  // parse container
234  try {
235  $this->parseEBML($info);
236  } catch (Exception $e) {
237  $this->error('EBML parser: '.$e->getMessage());
238  }
239 
240  // calculate playtime
241  if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
242  foreach ($info['matroska']['info'] as $key => $infoarray) {
243  if (isset($infoarray['Duration'])) {
244  // TimecodeScale is how many nanoseconds each Duration unit is
245  $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
246  break;
247  }
248  }
249  }
250 
251  // extract tags
252  if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
253  foreach ($info['matroska']['tags'] as $key => $infoarray) {
254  $this->ExtractCommentsSimpleTag($infoarray);
255  }
256  }
257 
258  // process tracks
259  if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
260  foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
261 
262  $track_info = array();
263  $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
264  $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true);
265  if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; }
266 
267  switch ($trackarray['TrackType']) {
268 
269  case 1: // Video
270  $track_info['resolution_x'] = $trackarray['PixelWidth'];
271  $track_info['resolution_y'] = $trackarray['PixelHeight'];
272  $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0);
273  $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']);
274  $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']);
275 
276  if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; }
277  if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; }
278  if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; }
279  if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; }
280  if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); }
281  if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
282 
283  switch ($trackarray['CodecID']) {
284  case 'V_MS/VFW/FOURCC':
285  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
286 
287  $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
288  $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']);
289  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
290  break;
291 
292  /*case 'V_MPEG4/ISO/AVC':
293  $h264['profile'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1));
294  $h264['level'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1));
295  $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1));
296  $h264['NALUlength'] = ($rn & 3) + 1;
297  $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1));
298  $nsps = ($rn & 31);
299  $offset = 6;
300  for ($i = 0; $i < $nsps; $i ++) {
301  $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
302  $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
303  $offset += 2 + $length;
304  }
305  $npps = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1));
306  $offset += 1;
307  for ($i = 0; $i < $npps; $i ++) {
308  $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
309  $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
310  $offset += 2 + $length;
311  }
312  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264;
313  break;*/
314  }
315 
316  $info['video']['streams'][] = $track_info;
317  break;
318 
319  case 2: // Audio
320  $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0);
321  $track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1);
322  $track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng');
323  if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; }
324  if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
325 
326  switch ($trackarray['CodecID']) {
327  case 'A_PCM/INT/LIT':
328  case 'A_PCM/INT/BIG':
329  $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
330  break;
331 
332  case 'A_AC3':
333  case 'A_EAC3':
334  case 'A_DTS':
335  case 'A_MPEG/L3':
336  case 'A_MPEG/L2':
337  case 'A_FLAC':
338  $module_dataformat = ($track_info['dataformat'] == 'mp2' ? 'mp3' : ($track_info['dataformat'] == 'eac3' ? 'ac3' : $track_info['dataformat']));
339  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.$module_dataformat.'.php', __FILE__, true);
340 
341  if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
342  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
343  break;
344  }
345 
346  // create temp instance
347  $getid3_temp = new getID3();
348  if ($track_info['dataformat'] != 'flac') {
349  $getid3_temp->openfile($this->getid3->filename);
350  }
351  $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
352  if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
353  $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
354  }
355 
356  // analyze
357  $class = 'getid3_'.$module_dataformat;
358  $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
359  $getid3_audio = new $class($getid3_temp, __CLASS__);
360  if ($track_info['dataformat'] == 'flac') {
361  $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
362  }
363  else {
364  $getid3_audio->Analyze();
365  }
366  if (!empty($getid3_temp->info[$header_data_key])) {
367  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
368  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
369  foreach ($getid3_temp->info['audio'] as $key => $value) {
370  $track_info[$key] = $value;
371  }
372  }
373  }
374  else {
375  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']);
376  }
377 
378  // copy errors and warnings
379  if (!empty($getid3_temp->info['error'])) {
380  foreach ($getid3_temp->info['error'] as $newerror) {
381  $this->warning($class.'() says: ['.$newerror.']');
382  }
383  }
384  if (!empty($getid3_temp->info['warning'])) {
385  foreach ($getid3_temp->info['warning'] as $newerror) {
386  $this->warning($class.'() says: ['.$newerror.']');
387  }
388  }
389  unset($getid3_temp, $getid3_audio);
390  break;
391 
392  case 'A_AAC':
393  case 'A_AAC/MPEG2/LC':
394  case 'A_AAC/MPEG2/LC/SBR':
395  case 'A_AAC/MPEG4/LC':
396  case 'A_AAC/MPEG4/LC/SBR':
397  $this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
398  break;
399 
400  case 'A_VORBIS':
401  if (!isset($trackarray['CodecPrivate'])) {
402  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set');
403  break;
404  }
405  $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
406  if ($vorbis_offset === false) {
407  $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword');
408  break;
409  }
410  $vorbis_offset -= 1;
411 
412  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
413 
414  // create temp instance
415  $getid3_temp = new getID3();
416 
417  // analyze
418  $getid3_ogg = new getid3_ogg($getid3_temp);
419  $oggpageinfo['page_seqno'] = 0;
420  $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
421  if (!empty($getid3_temp->info['ogg'])) {
422  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
423  if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
424  foreach ($getid3_temp->info['audio'] as $key => $value) {
425  $track_info[$key] = $value;
426  }
427  }
428  }
429 
430  // copy errors and warnings
431  if (!empty($getid3_temp->info['error'])) {
432  foreach ($getid3_temp->info['error'] as $newerror) {
433  $this->warning('getid3_ogg() says: ['.$newerror.']');
434  }
435  }
436  if (!empty($getid3_temp->info['warning'])) {
437  foreach ($getid3_temp->info['warning'] as $newerror) {
438  $this->warning('getid3_ogg() says: ['.$newerror.']');
439  }
440  }
441 
442  if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
443  $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
444  }
445  unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
446  break;
447 
448  case 'A_MS/ACM':
449  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
450 
451  $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
452  foreach ($parsed as $key => $value) {
453  if ($key != 'raw') {
454  $track_info[$key] = $value;
455  }
456  }
457  $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
458  break;
459 
460  default:
461  $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
462  break;
463  }
464 
465  $info['audio']['streams'][] = $track_info;
466  break;
467  }
468  }
469 
470  if (!empty($info['video']['streams'])) {
471  $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
472  }
473  if (!empty($info['audio']['streams'])) {
474  $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
475  }
476  }
477 
478  // process attachments
479  if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) {
480  foreach ($info['matroska']['attachments'] as $i => $entry) {
481  if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
482  $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']);
483  }
484  }
485  }
486 
487  // determine mime type
488  if (!empty($info['video']['streams'])) {
489  $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska');
490  } elseif (!empty($info['audio']['streams'])) {
491  $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska');
492  } elseif (isset($info['mime_type'])) {
493  unset($info['mime_type']);
494  }
495 
496  return true;
497  }
498 
499  private function parseEBML(&$info) {
500  // http://www.matroska.org/technical/specs/index.html#EBMLBasics
501  $this->current_offset = $info['avdataoffset'];
502 
503  while ($this->getEBMLelement($top_element, $info['avdataend'])) {
504  switch ($top_element['id']) {
505 
506  case EBML_ID_EBML:
507  $info['matroska']['header']['offset'] = $top_element['offset'];
508  $info['matroska']['header']['length'] = $top_element['length'];
509 
510  while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
511  switch ($element_data['id']) {
512 
513  case EBML_ID_EBMLVERSION:
519  $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']);
520  break;
521 
522  case EBML_ID_DOCTYPE:
523  $element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
524  $info['matroska']['doctype'] = $element_data['data'];
525  $info['fileformat'] = $element_data['data'];
526  break;
527 
528  default:
529  $this->unhandledElement('header', __LINE__, $element_data);
530  break;
531  }
532 
533  unset($element_data['offset'], $element_data['end']);
534  $info['matroska']['header']['elements'][] = $element_data;
535  }
536  break;
537 
538  case EBML_ID_SEGMENT:
539  $info['matroska']['segment'][0]['offset'] = $top_element['offset'];
540  $info['matroska']['segment'][0]['length'] = $top_element['length'];
541 
542  while ($this->getEBMLelement($element_data, $top_element['end'])) {
543  if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
544  $info['matroska']['segments'][] = $element_data;
545  }
546  switch ($element_data['id']) {
547 
548  case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements.
549 
550  while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
551  switch ($seek_entry['id']) {
552 
553  case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
554  while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
555 
556  switch ($sub_seek_entry['id']) {
557 
558  case EBML_ID_SEEKID:
559  $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']);
560  $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
561  break;
562 
564  $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']);
565  break;
566 
567  default:
568  $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
569  break;
570  }
571  if (!isset($seek_entry['target_id'])) {
572  $this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
573  break;
574  }
575  if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
576  $info['matroska']['seek'][] = $seek_entry;
577  }
578  break;
579 
580  default:
581  $this->unhandledElement('seekhead', __LINE__, $seek_entry);
582  break;
583  }
584  }
585  break;
586 
587  case EBML_ID_TRACKS: // A top-level block of information with many tracks described.
588  $info['matroska']['tracks'] = $element_data;
589 
590  while ($this->getEBMLelement($track_entry, $element_data['end'])) {
591  switch ($track_entry['id']) {
592 
593  case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
594 
595  while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
596  switch ($subelement['id']) {
597 
598  case EBML_ID_TRACKNUMBER:
599  case EBML_ID_TRACKUID:
600  case EBML_ID_TRACKTYPE:
601  case EBML_ID_MINCACHE:
602  case EBML_ID_MAXCACHE:
604  case EBML_ID_DEFAULTDURATION: // nanoseconds per frame
605  $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
606  break;
607 
609  $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
610  break;
611 
612  case EBML_ID_CODECID:
613  case EBML_ID_LANGUAGE:
614  case EBML_ID_NAME:
615  case EBML_ID_CODECNAME:
616  $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
617  break;
618 
620  $track_entry[$subelement['id_name']] = $this->readEBMLelementData($subelement['length'], true);
621  break;
622 
623  case EBML_ID_FLAGENABLED:
624  case EBML_ID_FLAGDEFAULT:
625  case EBML_ID_FLAGFORCED:
626  case EBML_ID_FLAGLACING:
628  $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']);
629  break;
630 
631  case EBML_ID_VIDEO:
632 
633  while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
634  switch ($sub_subelement['id']) {
635 
636  case EBML_ID_PIXELWIDTH:
637  case EBML_ID_PIXELHEIGHT:
644  case EBML_ID_DISPLAYUNIT:
646  case EBML_ID_STEREOMODE:
648  $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
649  break;
650 
652  $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
653  break;
654 
655  case EBML_ID_GAMMAVALUE:
656  $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
657  break;
658 
659  case EBML_ID_COLOURSPACE:
660  $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
661  break;
662 
663  default:
664  $this->unhandledElement('track.video', __LINE__, $sub_subelement);
665  break;
666  }
667  }
668  break;
669 
670  case EBML_ID_AUDIO:
671 
672  while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
673  switch ($sub_subelement['id']) {
674 
675  case EBML_ID_CHANNELS:
676  case EBML_ID_BITDEPTH:
677  $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
678  break;
679 
682  $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
683  break;
684 
686  $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
687  break;
688 
689  default:
690  $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
691  break;
692  }
693  }
694  break;
695 
697 
698  while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
699  switch ($sub_subelement['id']) {
700 
702 
703  while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
704  switch ($sub_sub_subelement['id']) {
705 
709  $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
710  break;
711 
713 
714  while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
715  switch ($sub_sub_sub_subelement['id']) {
716 
718  $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
719  break;
720 
722  $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
723  break;
724 
725  default:
726  $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
727  break;
728  }
729  }
730  break;
731 
733 
734  while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
735  switch ($sub_sub_sub_subelement['id']) {
736 
740  $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
741  break;
742 
746  $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
747  break;
748 
749  default:
750  $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
751  break;
752  }
753  }
754  break;
755 
756  default:
757  $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
758  break;
759  }
760  }
761  break;
762 
763  default:
764  $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
765  break;
766  }
767  }
768  break;
769 
770  default:
771  $this->unhandledElement('track', __LINE__, $subelement);
772  break;
773  }
774  }
775 
776  $info['matroska']['tracks']['tracks'][] = $track_entry;
777  break;
778 
779  default:
780  $this->unhandledElement('tracks', __LINE__, $track_entry);
781  break;
782  }
783  }
784  break;
785 
786  case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file.
787  $info_entry = array();
788 
789  while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
790  switch ($subelement['id']) {
791 
793  $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
794  break;
795 
796  case EBML_ID_DURATION:
797  $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
798  break;
799 
800  case EBML_ID_DATEUTC:
801  $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
802  $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]);
803  break;
804 
805  case EBML_ID_SEGMENTUID:
806  case EBML_ID_PREVUID:
807  case EBML_ID_NEXTUID:
808  $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
809  break;
810 
812  $info_entry[$subelement['id_name']][] = getid3_lib::trimNullByte($subelement['data']);
813  break;
814 
818  case EBML_ID_TITLE:
819  case EBML_ID_MUXINGAPP:
820  case EBML_ID_WRITINGAPP:
821  $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
822  $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']];
823  break;
824 
826  $chaptertranslate_entry = array();
827 
828  while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
829  switch ($sub_subelement['id']) {
830 
832  $chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']);
833  break;
834 
836  $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
837  break;
838 
840  $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
841  break;
842 
843  default:
844  $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement);
845  break;
846  }
847  }
848  $info_entry[$subelement['id_name']] = $chaptertranslate_entry;
849  break;
850 
851  default:
852  $this->unhandledElement('info', __LINE__, $subelement);
853  break;
854  }
855  }
856  $info['matroska']['info'][] = $info_entry;
857  break;
858 
859  case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams.
860  if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
861  $this->current_offset = $element_data['end'];
862  break;
863  }
864  $cues_entry = array();
865 
866  while ($this->getEBMLelement($subelement, $element_data['end'])) {
867  switch ($subelement['id']) {
868 
869  case EBML_ID_CUEPOINT:
870  $cuepoint_entry = array();
871 
872  while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
873  switch ($sub_subelement['id']) {
874 
876  $cuetrackpositions_entry = array();
877 
878  while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
879  switch ($sub_sub_subelement['id']) {
880 
881  case EBML_ID_CUETRACK:
885  $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
886  break;
887 
888  default:
889  $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
890  break;
891  }
892  }
893  $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
894  break;
895 
896  case EBML_ID_CUETIME:
897  $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
898  break;
899 
900  default:
901  $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
902  break;
903  }
904  }
905  $cues_entry[] = $cuepoint_entry;
906  break;
907 
908  default:
909  $this->unhandledElement('cues', __LINE__, $subelement);
910  break;
911  }
912  }
913  $info['matroska']['cues'] = $cues_entry;
914  break;
915 
916  case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters.
917  $tags_entry = array();
918 
919  while ($this->getEBMLelement($subelement, $element_data['end'], false)) {
920  switch ($subelement['id']) {
921 
922  case EBML_ID_TAG:
923  $tag_entry = array();
924 
925  while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) {
926  switch ($sub_subelement['id']) {
927 
928  case EBML_ID_TARGETS:
929  $targets_entry = array();
930 
931  while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
932  switch ($sub_sub_subelement['id']) {
933 
935  $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
936  $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
937  break;
938 
939  case EBML_ID_TARGETTYPE:
940  $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
941  break;
942 
943  case EBML_ID_TAGTRACKUID:
947  $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
948  break;
949 
950  default:
951  $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
952  break;
953  }
954  }
955  $tag_entry[$sub_subelement['id_name']] = $targets_entry;
956  break;
957 
958  case EBML_ID_SIMPLETAG:
959  $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']);
960  break;
961 
962  default:
963  $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
964  break;
965  }
966  }
967  $tags_entry[] = $tag_entry;
968  break;
969 
970  default:
971  $this->unhandledElement('tags', __LINE__, $subelement);
972  break;
973  }
974  }
975  $info['matroska']['tags'] = $tags_entry;
976  break;
977 
978  case EBML_ID_ATTACHMENTS: // Contain attached files.
979 
980  while ($this->getEBMLelement($subelement, $element_data['end'])) {
981  switch ($subelement['id']) {
982 
984  $attachedfile_entry = array();
985 
986  while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
987  switch ($sub_subelement['id']) {
988 
990  case EBML_ID_FILENAME:
992  $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
993  break;
994 
995  case EBML_ID_FILEDATA:
996  $attachedfile_entry['data_offset'] = $this->current_offset;
997  $attachedfile_entry['data_length'] = $sub_subelement['length'];
998 
999  $attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment(
1000  $attachedfile_entry['FileName'],
1001  $attachedfile_entry['data_offset'],
1002  $attachedfile_entry['data_length']);
1003 
1004  $this->current_offset = $sub_subelement['end'];
1005  break;
1006 
1007  case EBML_ID_FILEUID:
1008  $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
1009  break;
1010 
1011  default:
1012  $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
1013  break;
1014  }
1015  }
1016  $info['matroska']['attachments'][] = $attachedfile_entry;
1017  break;
1018 
1019  default:
1020  $this->unhandledElement('attachments', __LINE__, $subelement);
1021  break;
1022  }
1023  }
1024  break;
1025 
1026  case EBML_ID_CHAPTERS:
1027 
1028  while ($this->getEBMLelement($subelement, $element_data['end'])) {
1029  switch ($subelement['id']) {
1030 
1031  case EBML_ID_EDITIONENTRY:
1032  $editionentry_entry = array();
1033 
1034  while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
1035  switch ($sub_subelement['id']) {
1036 
1037  case EBML_ID_EDITIONUID:
1038  $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
1039  break;
1040 
1044  $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
1045  break;
1046 
1047  case EBML_ID_CHAPTERATOM:
1048  $chapteratom_entry = array();
1049 
1050  while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
1051  switch ($sub_sub_subelement['id']) {
1052 
1055  $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
1056  break;
1057 
1060  $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
1061  break;
1062 
1063  case EBML_ID_CHAPTERUID:
1066  $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
1067  break;
1068 
1069  case EBML_ID_CHAPTERTRACK:
1070  $chaptertrack_entry = array();
1071 
1072  while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
1073  switch ($sub_sub_sub_subelement['id']) {
1074 
1076  $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
1077  break;
1078 
1079  default:
1080  $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
1081  break;
1082  }
1083  }
1084  $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
1085  break;
1086 
1088  $chapterdisplay_entry = array();
1089 
1090  while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
1091  switch ($sub_sub_sub_subelement['id']) {
1092 
1093  case EBML_ID_CHAPSTRING:
1094  case EBML_ID_CHAPLANGUAGE:
1095  case EBML_ID_CHAPCOUNTRY:
1096  $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
1097  break;
1098 
1099  default:
1100  $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
1101  break;
1102  }
1103  }
1104  $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
1105  break;
1106 
1107  default:
1108  $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
1109  break;
1110  }
1111  }
1112  $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
1113  break;
1114 
1115  default:
1116  $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
1117  break;
1118  }
1119  }
1120  $info['matroska']['chapters'][] = $editionentry_entry;
1121  break;
1122 
1123  default:
1124  $this->unhandledElement('chapters', __LINE__, $subelement);
1125  break;
1126  }
1127  }
1128  break;
1129 
1130  case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure.
1131  $cluster_entry = array();
1132 
1133  while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
1134  switch ($subelement['id']) {
1135 
1139  $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
1140  break;
1141 
1143  $cluster_silent_tracks = array();
1144 
1145  while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
1146  switch ($sub_subelement['id']) {
1147 
1149  $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
1150  break;
1151 
1152  default:
1153  $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
1154  break;
1155  }
1156  }
1157  $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
1158  break;
1159 
1161  $cluster_block_group = array('offset' => $this->current_offset);
1162 
1163  while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
1164  switch ($sub_subelement['id']) {
1165 
1166  case EBML_ID_CLUSTERBLOCK:
1167  $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info);
1168  break;
1169 
1170  case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int
1171  case EBML_ID_CLUSTERBLOCKDURATION: // unsigned-int
1172  $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
1173  break;
1174 
1175  case EBML_ID_CLUSTERREFERENCEBLOCK: // signed-int
1176  $cluster_block_group[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true);
1177  break;
1178 
1180  $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
1181  break;
1182 
1183  default:
1184  $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
1185  break;
1186  }
1187  }
1188  $cluster_entry[$subelement['id_name']][] = $cluster_block_group;
1189  break;
1190 
1192  $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info);
1193  break;
1194 
1195  default:
1196  $this->unhandledElement('cluster', __LINE__, $subelement);
1197  break;
1198  }
1199  $this->current_offset = $subelement['end'];
1200  }
1201  if (!self::$hide_clusters) {
1202  $info['matroska']['cluster'][] = $cluster_entry;
1203  }
1204 
1205  // check to see if all the data we need exists already, if so, break out of the loop
1206  if (!self::$parse_whole_file) {
1207  if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
1208  if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
1209  if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
1210  return;
1211  }
1212  }
1213  }
1214  }
1215  break;
1216 
1217  default:
1218  $this->unhandledElement('segment', __LINE__, $element_data);
1219  break;
1220  }
1221  }
1222  break;
1223 
1224  default:
1225  $this->unhandledElement('root', __LINE__, $top_element);
1226  break;
1227  }
1228  }
1229  }
1230 
1231  private function EnsureBufferHasEnoughData($min_data=1024) {
1232  if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
1233  $read_bytes = max($min_data, $this->getid3->fread_buffer_size());
1234 
1235  try {
1236  $this->fseek($this->current_offset);
1237  $this->EBMLbuffer_offset = $this->current_offset;
1238  $this->EBMLbuffer = $this->fread($read_bytes);
1239  $this->EBMLbuffer_length = strlen($this->EBMLbuffer);
1240  } catch (getid3_exception $e) {
1241  $this->warning('EBML parser: '.$e->getMessage());
1242  return false;
1243  }
1244 
1245  if ($this->EBMLbuffer_length == 0 && $this->feof()) {
1246  return $this->error('EBML parser: ran out of file at offset '.$this->current_offset);
1247  }
1248  }
1249  return true;
1250  }
1251 
1252  private function readEBMLint() {
1253  $actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
1254 
1255  // get length of integer
1256  $first_byte_int = ord($this->EBMLbuffer[$actual_offset]);
1257  if (0x80 & $first_byte_int) {
1258  $length = 1;
1259  } elseif (0x40 & $first_byte_int) {
1260  $length = 2;
1261  } elseif (0x20 & $first_byte_int) {
1262  $length = 3;
1263  } elseif (0x10 & $first_byte_int) {
1264  $length = 4;
1265  } elseif (0x08 & $first_byte_int) {
1266  $length = 5;
1267  } elseif (0x04 & $first_byte_int) {
1268  $length = 6;
1269  } elseif (0x02 & $first_byte_int) {
1270  $length = 7;
1271  } elseif (0x01 & $first_byte_int) {
1272  $length = 8;
1273  } else {
1274  throw new Exception('invalid EBML integer (leading 0x00) at '.$this->current_offset);
1275  }
1276 
1277  // read
1278  $int_value = self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length));
1279  $this->current_offset += $length;
1280 
1281  return $int_value;
1282  }
1283 
1284  private function readEBMLelementData($length, $check_buffer=false) {
1285  if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
1286  return false;
1287  }
1288  $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length);
1289  $this->current_offset += $length;
1290  return $data;
1291  }
1292 
1293  private function getEBMLelement(&$element, $parent_end, $get_data=false) {
1294  if ($this->current_offset >= $parent_end) {
1295  return false;
1296  }
1297 
1298  if (!$this->EnsureBufferHasEnoughData()) {
1299  $this->current_offset = PHP_INT_MAX; // do not exit parser right now, allow to finish current loop to gather maximum information
1300  return false;
1301  }
1302 
1303  $element = array();
1304 
1305  // set offset
1306  $element['offset'] = $this->current_offset;
1307 
1308  // get ID
1309  $element['id'] = $this->readEBMLint();
1310 
1311  // get name
1312  $element['id_name'] = self::EBMLidName($element['id']);
1313 
1314  // get length
1315  $element['length'] = $this->readEBMLint();
1316 
1317  // get end offset
1318  $element['end'] = $this->current_offset + $element['length'];
1319 
1320  // get raw data
1321  $dont_parse = (in_array($element['id'], $this->unuseful_elements) || $element['id_name'] == dechex($element['id']));
1322  if (($get_data === true || (is_array($get_data) && !in_array($element['id'], $get_data))) && !$dont_parse) {
1323  $element['data'] = $this->readEBMLelementData($element['length'], $element);
1324  }
1325 
1326  return true;
1327  }
1328 
1329  private function unhandledElement($type, $line, $element) {
1330  // warn only about unknown and missed elements, not about unuseful
1331  if (!in_array($element['id'], $this->unuseful_elements)) {
1332  $this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']);
1333  }
1334 
1335  // increase offset for unparsed elements
1336  if (!isset($element['data'])) {
1337  $this->current_offset = $element['end'];
1338  }
1339  }
1340 
1341  private function ExtractCommentsSimpleTag($SimpleTagArray) {
1342  if (!empty($SimpleTagArray['SimpleTag'])) {
1343  foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
1344  if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) {
1345  $this->getid3->info['matroska']['comments'][strtolower($SimpleTagData['TagName'])][] = $SimpleTagData['TagString'];
1346  }
1347  if (!empty($SimpleTagData['SimpleTag'])) {
1348  $this->ExtractCommentsSimpleTag($SimpleTagData);
1349  }
1350  }
1351  }
1352 
1353  return true;
1354  }
1355 
1356  private function HandleEMBLSimpleTag($parent_end) {
1357  $simpletag_entry = array();
1358 
1359  while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) {
1360  switch ($element['id']) {
1361 
1362  case EBML_ID_TAGNAME:
1363  case EBML_ID_TAGLANGUAGE:
1364  case EBML_ID_TAGSTRING:
1365  case EBML_ID_TAGBINARY:
1366  $simpletag_entry[$element['id_name']] = $element['data'];
1367  break;
1368 
1369  case EBML_ID_SIMPLETAG:
1370  $simpletag_entry[$element['id_name']][] = $this->HandleEMBLSimpleTag($element['end']);
1371  break;
1372 
1373  case EBML_ID_TAGDEFAULT:
1374  $simpletag_entry[$element['id_name']] = (bool)getid3_lib::BigEndian2Int($element['data']);
1375  break;
1376 
1377  default:
1378  $this->unhandledElement('tag.simpletag', __LINE__, $element);
1379  break;
1380  }
1381  }
1382 
1383  return $simpletag_entry;
1384  }
1385 
1386  private function HandleEMBLClusterBlock($element, $block_type, &$info) {
1387  // http://www.matroska.org/technical/specs/index.html#block_structure
1388  // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
1389 
1390  $block_data = array();
1391  $block_data['tracknumber'] = $this->readEBMLint();
1392  $block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true);
1393  $block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
1394 
1395  if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
1396  $block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7);
1397  //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4);
1398  }
1399  else {
1400  //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4);
1401  }
1402  $block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3);
1403  $block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
1404  if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
1405  $block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01));
1406  }
1407  else {
1408  //$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0);
1409  }
1410  $block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']);
1411 
1412  // Lace (when lacing bit is set)
1413  if ($block_data['flags']['lacing'] > 0) {
1414  $block_data['lace_frames'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)) + 1; // Number of frames in the lace-1 (uint8)
1415  if ($block_data['flags']['lacing'] != 0x02) {
1416  for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
1417  if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing
1418  $block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing.
1419  }
1420  else { // Xiph lacing
1421  $block_data['lace_frames_size'][$i] = 0;
1422  do {
1424  $block_data['lace_frames_size'][$i] += $size;
1425  }
1426  while ($size == 255);
1427  }
1428  }
1429  if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly
1430  $block_data['lace_frames_size'][] = $element['end'] - $this->current_offset - array_sum($block_data['lace_frames_size']);
1431  }
1432  }
1433  }
1434 
1435  if (!isset($info['matroska']['track_data_offsets'][$block_data['tracknumber']])) {
1436  $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['offset'] = $this->current_offset;
1437  $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'] = $element['end'] - $this->current_offset;
1438  //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] = 0;
1439  }
1440  //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] += $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'];
1441  //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['duration'] = $block_data['timecode'] * ((isset($info['matroska']['info'][0]['TimecodeScale']) ? $info['matroska']['info'][0]['TimecodeScale'] : 1000000) / 1000000000);
1442 
1443  // set offset manually
1444  $this->current_offset = $element['end'];
1445 
1446  return $block_data;
1447  }
1448 
1449  private static function EBML2Int($EBMLstring) {
1450  // http://matroska.org/specs/
1451 
1452  // Element ID coded with an UTF-8 like system:
1453  // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X)
1454  // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX)
1455  // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX)
1456  // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX)
1457  // Values with all x at 0 and 1 are reserved (hence the -2).
1458 
1459  // Data size, in octets, is also coded with an UTF-8 like system :
1460  // 1xxx xxxx - value 0 to 2^7-2
1461  // 01xx xxxx xxxx xxxx - value 0 to 2^14-2
1462  // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2
1463  // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2
1464  // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2
1465  // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2
1466  // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2
1467  // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2
1468 
1469  $first_byte_int = ord($EBMLstring[0]);
1470  if (0x80 & $first_byte_int) {
1471  $EBMLstring[0] = chr($first_byte_int & 0x7F);
1472  } elseif (0x40 & $first_byte_int) {
1473  $EBMLstring[0] = chr($first_byte_int & 0x3F);
1474  } elseif (0x20 & $first_byte_int) {
1475  $EBMLstring[0] = chr($first_byte_int & 0x1F);
1476  } elseif (0x10 & $first_byte_int) {
1477  $EBMLstring[0] = chr($first_byte_int & 0x0F);
1478  } elseif (0x08 & $first_byte_int) {
1479  $EBMLstring[0] = chr($first_byte_int & 0x07);
1480  } elseif (0x04 & $first_byte_int) {
1481  $EBMLstring[0] = chr($first_byte_int & 0x03);
1482  } elseif (0x02 & $first_byte_int) {
1483  $EBMLstring[0] = chr($first_byte_int & 0x01);
1484  } elseif (0x01 & $first_byte_int) {
1485  $EBMLstring[0] = chr($first_byte_int & 0x00);
1486  }
1487 
1488  return getid3_lib::BigEndian2Int($EBMLstring);
1489  }
1490 
1491  private static function EBMLdate2unix($EBMLdatestamp) {
1492  // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
1493  // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
1494  return round(($EBMLdatestamp / 1000000000) + 978307200);
1495  }
1496 
1497  public static function TargetTypeValue($target_type) {
1498  // http://www.matroska.org/technical/specs/tagging/index.html
1499  static $TargetTypeValue = array();
1500  if (empty($TargetTypeValue)) {
1501  $TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies
1502  $TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement)
1503  $TargetTypeValue[30] = 'A:track/song ~ V:chapter'; // the common parts of an album or a movie
1504  $TargetTypeValue[40] = 'A:part/session ~ V:part/session'; // when an album or episode has different logical parts
1505  $TargetTypeValue[50] = 'A:album/opera/concert ~ V:movie/episode/concert'; // the most common grouping level of music and video (equals to an episode for TV series)
1506  $TargetTypeValue[60] = 'A:edition/issue/volume/opus ~ V:season/sequel/volume'; // a list of lower levels grouped together
1507  $TargetTypeValue[70] = 'A:collection ~ V:collection'; // the high hierarchy consisting of many different lower items
1508  }
1509  return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
1510  }
1511 
1512  public static function BlockLacingType($lacingtype) {
1513  // http://matroska.org/technical/specs/index.html#block_structure
1514  static $BlockLacingType = array();
1515  if (empty($BlockLacingType)) {
1516  $BlockLacingType[0x00] = 'no lacing';
1517  $BlockLacingType[0x01] = 'Xiph lacing';
1518  $BlockLacingType[0x02] = 'fixed-size lacing';
1519  $BlockLacingType[0x03] = 'EBML lacing';
1520  }
1521  return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
1522  }
1523 
1524  public static function CodecIDtoCommonName($codecid) {
1525  // http://www.matroska.org/technical/specs/codecid/index.html
1526  static $CodecIDlist = array();
1527  if (empty($CodecIDlist)) {
1528  $CodecIDlist['A_AAC'] = 'aac';
1529  $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
1530  $CodecIDlist['A_AC3'] = 'ac3';
1531  $CodecIDlist['A_EAC3'] = 'eac3';
1532  $CodecIDlist['A_DTS'] = 'dts';
1533  $CodecIDlist['A_FLAC'] = 'flac';
1534  $CodecIDlist['A_MPEG/L1'] = 'mp1';
1535  $CodecIDlist['A_MPEG/L2'] = 'mp2';
1536  $CodecIDlist['A_MPEG/L3'] = 'mp3';
1537  $CodecIDlist['A_PCM/INT/LIT'] = 'pcm'; // PCM Integer Little Endian
1538  $CodecIDlist['A_PCM/INT/BIG'] = 'pcm'; // PCM Integer Big Endian
1539  $CodecIDlist['A_QUICKTIME/QDMC'] = 'quicktime'; // Quicktime: QDesign Music
1540  $CodecIDlist['A_QUICKTIME/QDM2'] = 'quicktime'; // Quicktime: QDesign Music v2
1541  $CodecIDlist['A_VORBIS'] = 'vorbis';
1542  $CodecIDlist['V_MPEG1'] = 'mpeg';
1543  $CodecIDlist['V_THEORA'] = 'theora';
1544  $CodecIDlist['V_REAL/RV40'] = 'real';
1545  $CodecIDlist['V_REAL/RV10'] = 'real';
1546  $CodecIDlist['V_REAL/RV20'] = 'real';
1547  $CodecIDlist['V_REAL/RV30'] = 'real';
1548  $CodecIDlist['V_QUICKTIME'] = 'quicktime'; // Quicktime
1549  $CodecIDlist['V_MPEG4/ISO/AP'] = 'mpeg4';
1550  $CodecIDlist['V_MPEG4/ISO/ASP'] = 'mpeg4';
1551  $CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264';
1552  $CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4';
1553  $CodecIDlist['V_VP8'] = 'vp8';
1554  $CodecIDlist['V_MS/VFW/FOURCC'] = 'vcm'; // Microsoft (TM) Video Codec Manager (VCM)
1555  $CodecIDlist['A_MS/ACM'] = 'acm'; // Microsoft (TM) Audio Codec Manager (ACM)
1556  }
1557  return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
1558  }
1559 
1560  private static function EBMLidName($value) {
1561  static $EBMLidList = array();
1562  if (empty($EBMLidList)) {
1563  $EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType';
1564  $EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile';
1565  $EBMLidList[EBML_ID_ATTACHMENTLINK] = 'AttachmentLink';
1566  $EBMLidList[EBML_ID_ATTACHMENTS] = 'Attachments';
1567  $EBMLidList[EBML_ID_AUDIO] = 'Audio';
1568  $EBMLidList[EBML_ID_BITDEPTH] = 'BitDepth';
1569  $EBMLidList[EBML_ID_CHANNELPOSITIONS] = 'ChannelPositions';
1570  $EBMLidList[EBML_ID_CHANNELS] = 'Channels';
1571  $EBMLidList[EBML_ID_CHAPCOUNTRY] = 'ChapCountry';
1572  $EBMLidList[EBML_ID_CHAPLANGUAGE] = 'ChapLanguage';
1573  $EBMLidList[EBML_ID_CHAPPROCESS] = 'ChapProcess';
1574  $EBMLidList[EBML_ID_CHAPPROCESSCODECID] = 'ChapProcessCodecID';
1575  $EBMLidList[EBML_ID_CHAPPROCESSCOMMAND] = 'ChapProcessCommand';
1576  $EBMLidList[EBML_ID_CHAPPROCESSDATA] = 'ChapProcessData';
1577  $EBMLidList[EBML_ID_CHAPPROCESSPRIVATE] = 'ChapProcessPrivate';
1578  $EBMLidList[EBML_ID_CHAPPROCESSTIME] = 'ChapProcessTime';
1579  $EBMLidList[EBML_ID_CHAPSTRING] = 'ChapString';
1580  $EBMLidList[EBML_ID_CHAPTERATOM] = 'ChapterAtom';
1581  $EBMLidList[EBML_ID_CHAPTERDISPLAY] = 'ChapterDisplay';
1582  $EBMLidList[EBML_ID_CHAPTERFLAGENABLED] = 'ChapterFlagEnabled';
1583  $EBMLidList[EBML_ID_CHAPTERFLAGHIDDEN] = 'ChapterFlagHidden';
1584  $EBMLidList[EBML_ID_CHAPTERPHYSICALEQUIV] = 'ChapterPhysicalEquiv';
1585  $EBMLidList[EBML_ID_CHAPTERS] = 'Chapters';
1586  $EBMLidList[EBML_ID_CHAPTERSEGMENTEDITIONUID] = 'ChapterSegmentEditionUID';
1587  $EBMLidList[EBML_ID_CHAPTERSEGMENTUID] = 'ChapterSegmentUID';
1588  $EBMLidList[EBML_ID_CHAPTERTIMEEND] = 'ChapterTimeEnd';
1589  $EBMLidList[EBML_ID_CHAPTERTIMESTART] = 'ChapterTimeStart';
1590  $EBMLidList[EBML_ID_CHAPTERTRACK] = 'ChapterTrack';
1591  $EBMLidList[EBML_ID_CHAPTERTRACKNUMBER] = 'ChapterTrackNumber';
1592  $EBMLidList[EBML_ID_CHAPTERTRANSLATE] = 'ChapterTranslate';
1593  $EBMLidList[EBML_ID_CHAPTERTRANSLATECODEC] = 'ChapterTranslateCodec';
1594  $EBMLidList[EBML_ID_CHAPTERTRANSLATEEDITIONUID] = 'ChapterTranslateEditionUID';
1595  $EBMLidList[EBML_ID_CHAPTERTRANSLATEID] = 'ChapterTranslateID';
1596  $EBMLidList[EBML_ID_CHAPTERUID] = 'ChapterUID';
1597  $EBMLidList[EBML_ID_CLUSTER] = 'Cluster';
1598  $EBMLidList[EBML_ID_CLUSTERBLOCK] = 'ClusterBlock';
1599  $EBMLidList[EBML_ID_CLUSTERBLOCKADDID] = 'ClusterBlockAddID';
1600  $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONAL] = 'ClusterBlockAdditional';
1601  $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONID] = 'ClusterBlockAdditionID';
1602  $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONS] = 'ClusterBlockAdditions';
1603  $EBMLidList[EBML_ID_CLUSTERBLOCKDURATION] = 'ClusterBlockDuration';
1604  $EBMLidList[EBML_ID_CLUSTERBLOCKGROUP] = 'ClusterBlockGroup';
1605  $EBMLidList[EBML_ID_CLUSTERBLOCKMORE] = 'ClusterBlockMore';
1606  $EBMLidList[EBML_ID_CLUSTERBLOCKVIRTUAL] = 'ClusterBlockVirtual';
1607  $EBMLidList[EBML_ID_CLUSTERCODECSTATE] = 'ClusterCodecState';
1608  $EBMLidList[EBML_ID_CLUSTERDELAY] = 'ClusterDelay';
1609  $EBMLidList[EBML_ID_CLUSTERDURATION] = 'ClusterDuration';
1610  $EBMLidList[EBML_ID_CLUSTERENCRYPTEDBLOCK] = 'ClusterEncryptedBlock';
1611  $EBMLidList[EBML_ID_CLUSTERFRAMENUMBER] = 'ClusterFrameNumber';
1612  $EBMLidList[EBML_ID_CLUSTERLACENUMBER] = 'ClusterLaceNumber';
1613  $EBMLidList[EBML_ID_CLUSTERPOSITION] = 'ClusterPosition';
1614  $EBMLidList[EBML_ID_CLUSTERPREVSIZE] = 'ClusterPrevSize';
1615  $EBMLidList[EBML_ID_CLUSTERREFERENCEBLOCK] = 'ClusterReferenceBlock';
1616  $EBMLidList[EBML_ID_CLUSTERREFERENCEPRIORITY] = 'ClusterReferencePriority';
1617  $EBMLidList[EBML_ID_CLUSTERREFERENCEVIRTUAL] = 'ClusterReferenceVirtual';
1618  $EBMLidList[EBML_ID_CLUSTERSILENTTRACKNUMBER] = 'ClusterSilentTrackNumber';
1619  $EBMLidList[EBML_ID_CLUSTERSILENTTRACKS] = 'ClusterSilentTracks';
1620  $EBMLidList[EBML_ID_CLUSTERSIMPLEBLOCK] = 'ClusterSimpleBlock';
1621  $EBMLidList[EBML_ID_CLUSTERTIMECODE] = 'ClusterTimecode';
1622  $EBMLidList[EBML_ID_CLUSTERTIMESLICE] = 'ClusterTimeSlice';
1623  $EBMLidList[EBML_ID_CODECDECODEALL] = 'CodecDecodeAll';
1624  $EBMLidList[EBML_ID_CODECDOWNLOADURL] = 'CodecDownloadURL';
1625  $EBMLidList[EBML_ID_CODECID] = 'CodecID';
1626  $EBMLidList[EBML_ID_CODECINFOURL] = 'CodecInfoURL';
1627  $EBMLidList[EBML_ID_CODECNAME] = 'CodecName';
1628  $EBMLidList[EBML_ID_CODECPRIVATE] = 'CodecPrivate';
1629  $EBMLidList[EBML_ID_CODECSETTINGS] = 'CodecSettings';
1630  $EBMLidList[EBML_ID_COLOURSPACE] = 'ColourSpace';
1631  $EBMLidList[EBML_ID_CONTENTCOMPALGO] = 'ContentCompAlgo';
1632  $EBMLidList[EBML_ID_CONTENTCOMPRESSION] = 'ContentCompression';
1633  $EBMLidList[EBML_ID_CONTENTCOMPSETTINGS] = 'ContentCompSettings';
1634  $EBMLidList[EBML_ID_CONTENTENCALGO] = 'ContentEncAlgo';
1635  $EBMLidList[EBML_ID_CONTENTENCKEYID] = 'ContentEncKeyID';
1636  $EBMLidList[EBML_ID_CONTENTENCODING] = 'ContentEncoding';
1637  $EBMLidList[EBML_ID_CONTENTENCODINGORDER] = 'ContentEncodingOrder';
1638  $EBMLidList[EBML_ID_CONTENTENCODINGS] = 'ContentEncodings';
1639  $EBMLidList[EBML_ID_CONTENTENCODINGSCOPE] = 'ContentEncodingScope';
1640  $EBMLidList[EBML_ID_CONTENTENCODINGTYPE] = 'ContentEncodingType';
1641  $EBMLidList[EBML_ID_CONTENTENCRYPTION] = 'ContentEncryption';
1642  $EBMLidList[EBML_ID_CONTENTSIGALGO] = 'ContentSigAlgo';
1643  $EBMLidList[EBML_ID_CONTENTSIGHASHALGO] = 'ContentSigHashAlgo';
1644  $EBMLidList[EBML_ID_CONTENTSIGKEYID] = 'ContentSigKeyID';
1645  $EBMLidList[EBML_ID_CONTENTSIGNATURE] = 'ContentSignature';
1646  $EBMLidList[EBML_ID_CRC32] = 'CRC32';
1647  $EBMLidList[EBML_ID_CUEBLOCKNUMBER] = 'CueBlockNumber';
1648  $EBMLidList[EBML_ID_CUECLUSTERPOSITION] = 'CueClusterPosition';
1649  $EBMLidList[EBML_ID_CUECODECSTATE] = 'CueCodecState';
1650  $EBMLidList[EBML_ID_CUEPOINT] = 'CuePoint';
1651  $EBMLidList[EBML_ID_CUEREFCLUSTER] = 'CueRefCluster';
1652  $EBMLidList[EBML_ID_CUEREFCODECSTATE] = 'CueRefCodecState';
1653  $EBMLidList[EBML_ID_CUEREFERENCE] = 'CueReference';
1654  $EBMLidList[EBML_ID_CUEREFNUMBER] = 'CueRefNumber';
1655  $EBMLidList[EBML_ID_CUEREFTIME] = 'CueRefTime';
1656  $EBMLidList[EBML_ID_CUES] = 'Cues';
1657  $EBMLidList[EBML_ID_CUETIME] = 'CueTime';
1658  $EBMLidList[EBML_ID_CUETRACK] = 'CueTrack';
1659  $EBMLidList[EBML_ID_CUETRACKPOSITIONS] = 'CueTrackPositions';
1660  $EBMLidList[EBML_ID_DATEUTC] = 'DateUTC';
1661  $EBMLidList[EBML_ID_DEFAULTDURATION] = 'DefaultDuration';
1662  $EBMLidList[EBML_ID_DISPLAYHEIGHT] = 'DisplayHeight';
1663  $EBMLidList[EBML_ID_DISPLAYUNIT] = 'DisplayUnit';
1664  $EBMLidList[EBML_ID_DISPLAYWIDTH] = 'DisplayWidth';
1665  $EBMLidList[EBML_ID_DOCTYPE] = 'DocType';
1666  $EBMLidList[EBML_ID_DOCTYPEREADVERSION] = 'DocTypeReadVersion';
1667  $EBMLidList[EBML_ID_DOCTYPEVERSION] = 'DocTypeVersion';
1668  $EBMLidList[EBML_ID_DURATION] = 'Duration';
1669  $EBMLidList[EBML_ID_EBML] = 'EBML';
1670  $EBMLidList[EBML_ID_EBMLMAXIDLENGTH] = 'EBMLMaxIDLength';
1671  $EBMLidList[EBML_ID_EBMLMAXSIZELENGTH] = 'EBMLMaxSizeLength';
1672  $EBMLidList[EBML_ID_EBMLREADVERSION] = 'EBMLReadVersion';
1673  $EBMLidList[EBML_ID_EBMLVERSION] = 'EBMLVersion';
1674  $EBMLidList[EBML_ID_EDITIONENTRY] = 'EditionEntry';
1675  $EBMLidList[EBML_ID_EDITIONFLAGDEFAULT] = 'EditionFlagDefault';
1676  $EBMLidList[EBML_ID_EDITIONFLAGHIDDEN] = 'EditionFlagHidden';
1677  $EBMLidList[EBML_ID_EDITIONFLAGORDERED] = 'EditionFlagOrdered';
1678  $EBMLidList[EBML_ID_EDITIONUID] = 'EditionUID';
1679  $EBMLidList[EBML_ID_FILEDATA] = 'FileData';
1680  $EBMLidList[EBML_ID_FILEDESCRIPTION] = 'FileDescription';
1681  $EBMLidList[EBML_ID_FILEMIMETYPE] = 'FileMimeType';
1682  $EBMLidList[EBML_ID_FILENAME] = 'FileName';
1683  $EBMLidList[EBML_ID_FILEREFERRAL] = 'FileReferral';
1684  $EBMLidList[EBML_ID_FILEUID] = 'FileUID';
1685  $EBMLidList[EBML_ID_FLAGDEFAULT] = 'FlagDefault';
1686  $EBMLidList[EBML_ID_FLAGENABLED] = 'FlagEnabled';
1687  $EBMLidList[EBML_ID_FLAGFORCED] = 'FlagForced';
1688  $EBMLidList[EBML_ID_FLAGINTERLACED] = 'FlagInterlaced';
1689  $EBMLidList[EBML_ID_FLAGLACING] = 'FlagLacing';
1690  $EBMLidList[EBML_ID_GAMMAVALUE] = 'GammaValue';
1691  $EBMLidList[EBML_ID_INFO] = 'Info';
1692  $EBMLidList[EBML_ID_LANGUAGE] = 'Language';
1693  $EBMLidList[EBML_ID_MAXBLOCKADDITIONID] = 'MaxBlockAdditionID';
1694  $EBMLidList[EBML_ID_MAXCACHE] = 'MaxCache';
1695  $EBMLidList[EBML_ID_MINCACHE] = 'MinCache';
1696  $EBMLidList[EBML_ID_MUXINGAPP] = 'MuxingApp';
1697  $EBMLidList[EBML_ID_NAME] = 'Name';
1698  $EBMLidList[EBML_ID_NEXTFILENAME] = 'NextFilename';
1699  $EBMLidList[EBML_ID_NEXTUID] = 'NextUID';
1700  $EBMLidList[EBML_ID_OUTPUTSAMPLINGFREQUENCY] = 'OutputSamplingFrequency';
1701  $EBMLidList[EBML_ID_PIXELCROPBOTTOM] = 'PixelCropBottom';
1702  $EBMLidList[EBML_ID_PIXELCROPLEFT] = 'PixelCropLeft';
1703  $EBMLidList[EBML_ID_PIXELCROPRIGHT] = 'PixelCropRight';
1704  $EBMLidList[EBML_ID_PIXELCROPTOP] = 'PixelCropTop';
1705  $EBMLidList[EBML_ID_PIXELHEIGHT] = 'PixelHeight';
1706  $EBMLidList[EBML_ID_PIXELWIDTH] = 'PixelWidth';
1707  $EBMLidList[EBML_ID_PREVFILENAME] = 'PrevFilename';
1708  $EBMLidList[EBML_ID_PREVUID] = 'PrevUID';
1709  $EBMLidList[EBML_ID_SAMPLINGFREQUENCY] = 'SamplingFrequency';
1710  $EBMLidList[EBML_ID_SEEK] = 'Seek';
1711  $EBMLidList[EBML_ID_SEEKHEAD] = 'SeekHead';
1712  $EBMLidList[EBML_ID_SEEKID] = 'SeekID';
1713  $EBMLidList[EBML_ID_SEEKPOSITION] = 'SeekPosition';
1714  $EBMLidList[EBML_ID_SEGMENT] = 'Segment';
1715  $EBMLidList[EBML_ID_SEGMENTFAMILY] = 'SegmentFamily';
1716  $EBMLidList[EBML_ID_SEGMENTFILENAME] = 'SegmentFilename';
1717  $EBMLidList[EBML_ID_SEGMENTUID] = 'SegmentUID';
1718  $EBMLidList[EBML_ID_SIMPLETAG] = 'SimpleTag';
1719  $EBMLidList[EBML_ID_CLUSTERSLICES] = 'ClusterSlices';
1720  $EBMLidList[EBML_ID_STEREOMODE] = 'StereoMode';
1721  $EBMLidList[EBML_ID_OLDSTEREOMODE] = 'OldStereoMode';
1722  $EBMLidList[EBML_ID_TAG] = 'Tag';
1723  $EBMLidList[EBML_ID_TAGATTACHMENTUID] = 'TagAttachmentUID';
1724  $EBMLidList[EBML_ID_TAGBINARY] = 'TagBinary';
1725  $EBMLidList[EBML_ID_TAGCHAPTERUID] = 'TagChapterUID';
1726  $EBMLidList[EBML_ID_TAGDEFAULT] = 'TagDefault';
1727  $EBMLidList[EBML_ID_TAGEDITIONUID] = 'TagEditionUID';
1728  $EBMLidList[EBML_ID_TAGLANGUAGE] = 'TagLanguage';
1729  $EBMLidList[EBML_ID_TAGNAME] = 'TagName';
1730  $EBMLidList[EBML_ID_TAGTRACKUID] = 'TagTrackUID';
1731  $EBMLidList[EBML_ID_TAGS] = 'Tags';
1732  $EBMLidList[EBML_ID_TAGSTRING] = 'TagString';
1733  $EBMLidList[EBML_ID_TARGETS] = 'Targets';
1734  $EBMLidList[EBML_ID_TARGETTYPE] = 'TargetType';
1735  $EBMLidList[EBML_ID_TARGETTYPEVALUE] = 'TargetTypeValue';
1736  $EBMLidList[EBML_ID_TIMECODESCALE] = 'TimecodeScale';
1737  $EBMLidList[EBML_ID_TITLE] = 'Title';
1738  $EBMLidList[EBML_ID_TRACKENTRY] = 'TrackEntry';
1739  $EBMLidList[EBML_ID_TRACKNUMBER] = 'TrackNumber';
1740  $EBMLidList[EBML_ID_TRACKOFFSET] = 'TrackOffset';
1741  $EBMLidList[EBML_ID_TRACKOVERLAY] = 'TrackOverlay';
1742  $EBMLidList[EBML_ID_TRACKS] = 'Tracks';
1743  $EBMLidList[EBML_ID_TRACKTIMECODESCALE] = 'TrackTimecodeScale';
1744  $EBMLidList[EBML_ID_TRACKTRANSLATE] = 'TrackTranslate';
1745  $EBMLidList[EBML_ID_TRACKTRANSLATECODEC] = 'TrackTranslateCodec';
1746  $EBMLidList[EBML_ID_TRACKTRANSLATEEDITIONUID] = 'TrackTranslateEditionUID';
1747  $EBMLidList[EBML_ID_TRACKTRANSLATETRACKID] = 'TrackTranslateTrackID';
1748  $EBMLidList[EBML_ID_TRACKTYPE] = 'TrackType';
1749  $EBMLidList[EBML_ID_TRACKUID] = 'TrackUID';
1750  $EBMLidList[EBML_ID_VIDEO] = 'Video';
1751  $EBMLidList[EBML_ID_VOID] = 'Void';
1752  $EBMLidList[EBML_ID_WRITINGAPP] = 'WritingApp';
1753  }
1754 
1755  return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
1756  }
1757 
1758  public static function displayUnit($value) {
1759  // http://www.matroska.org/technical/specs/index.html#DisplayUnit
1760  static $units = array(
1761  0 => 'pixels',
1762  1 => 'centimeters',
1763  2 => 'inches',
1764  3 => 'Display Aspect Ratio');
1765 
1766  return (isset($units[$value]) ? $units[$value] : 'unknown');
1767  }
1768 
1769  private static function getDefaultStreamInfo($streams)
1770  {
1771  foreach (array_reverse($streams) as $stream) {
1772  if ($stream['default']) {
1773  break;
1774  }
1775  }
1776 
1777  $unset = array('default', 'name');
1778  foreach ($unset as $u) {
1779  if (isset($stream[$u])) {
1780  unset($stream[$u]);
1781  }
1782  }
1783 
1784  $info = $stream;
1785  $info['streams'] = $streams;
1786 
1787  return $info;
1788  }
1789 
1790 }
const EBML_ID_CONTENTSIGALGO
const EBML_ID_CUECLUSTERPOSITION
const EBML_ID_CLUSTERCODECSTATE
const EBML_ID_TRACKNUMBER
const EBML_ID_CLUSTERPREVSIZE
const EBML_ID_CHAPPROCESSCODECID
const EBML_ID_CONTENTSIGNATURE
const EBML_ID_DISPLAYUNIT
const EBML_ID_TARGETTYPEVALUE
const EBML_ID_CLUSTERDURATION
const EBML_ID_TAGBINARY
const EBML_ID_FLAGFORCED
const EBML_ID_PREVUID
const EBML_ID_CHAPTERDISPLAY
const EBML_ID_SAMPLINGFREQUENCY
const EBML_ID_ATTACHMENTLINK
$size
Definition: RandomTest.php:84
const EBML_ID_CONTENTENCODING
const EBML_ID_ASPECTRATIOTYPE
const EBML_ID_GAMMAVALUE
const EBML_ID_CHAPTERTRANSLATEID
const EBML_ID_CLUSTERBLOCKADDITIONAL
const EBML_ID_CHAPTERFLAGENABLED
const EBML_ID_TAGSTRING
const EBML_ID_COLOURSPACE
const EBML_ID_CONTENTENCODINGSCOPE
const EBML_ID_CUEREFTIME
const EBML_ID_CLUSTERSILENTTRACKS
const EBML_ID_SEEKHEAD
const EBML_ID_CHAPPROCESSPRIVATE
$target_type
Definition: goto.php:48
const EBML_ID_ATTACHEDFILE
const EBML_ID_TRACKOVERLAY
static ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true)
const ATTACHMENTS_NONE
Definition: getid3.php:118
const EBML_ID_CONTENTENCKEYID
const EBML_ID_FILEDATA
const EBML_ID_EDITIONENTRY
const EBML_ID_CODECPRIVATE
$type
const EBML_ID_CLUSTERSIMPLEBLOCK
const EBML_ID_CONTENTENCODINGORDER
const EBML_ID_SEEKPOSITION
const EBML_ID_CUEREFERENCE
const EBML_ID_CONTENTCOMPALGO
const EBML_ID_TRACKTRANSLATECODEC
const EBML_ID_CHAPLANGUAGE
HandleEMBLClusterBlock($element, $block_type, &$info)
error($text)
Definition: getid3.php:1752
const EBML_ID_CONTENTENCODINGTYPE
const EBML_ID_FILEREFERRAL
const EBML_ID_TRACKUID
const EBML_ID_CLUSTERREFERENCEVIRTUAL
const EBML_ID_CODECNAME
const EBML_ID_CHAPPROCESSCOMMAND
const EBML_ID_CODECDOWNLOADURL
const EBML_ID_CHAPTERUID
const EBML_ID_PIXELHEIGHT
const EBML_ID_NEXTUID
const EBML_ID_FLAGENABLED
const EBML_ID_CLUSTERENCRYPTEDBLOCK
const EBML_ID_TRACKS
warning($text)
Definition: getid3.php:1758
const EBML_ID_CLUSTERBLOCKADDID
saveAttachment($name, $offset, $length, $image_mime=null)
Definition: getid3.php:1766
static parseWAVEFORMATex($WaveFormatExData)
const EBML_ID_CONTENTSIGHASHALGO
const EBML_ID_PIXELCROPRIGHT
const EBML_ID_CLUSTERBLOCK
const EBML_ID_NEXTFILENAME
const EBML_ID_TAGEDITIONUID
static EBMLdate2unix($EBMLdatestamp)
const EBML_ID_CHAPTERTRACKNUMBER
const EBML_ID_CHAPTERPHYSICALEQUIV
const EBML_ID_SIMPLETAG
const EBML_ID_EDITIONFLAGHIDDEN
$stream
PHP stream implementation.
const EBML_ID_SEGMENTUID
const EBML_ID_CUETRACKPOSITIONS
const EBML_ID_CUEREFNUMBER
const EBML_ID_TAGNAME
static IncludeDependency($filename, $sourcefile, $DieOnFailure=false)
const EBML_ID_DEFAULTDURATION
const EBML_ID_MINCACHE
const EBML_ID_CHAPTERSEGMENTUID
const EBML_ID_CUEPOINT
static fourccLookup($fourcc)
getEBMLelement(&$element, $parent_end, $get_data=false)
const EBML_ID_LANGUAGE
const EBML_ID_CHAPTERFLAGHIDDEN
const EBML_ID_CHAPTERTIMESTART
const EBML_ID_SEGMENT
const EBML_ID_DISPLAYWIDTH
const EBML_ID_TAGCHAPTERUID
const EBML_ID_CODECSETTINGS
const EBML_ID_CHAPCOUNTRY
static BigEndian2Float($byteword)
Definition: getid3.lib.php:185
const EBML_ID_CHAPTERTIMEEND
const EBML_ID_EDITIONFLAGDEFAULT
const EBML_ID_CLUSTERSLICES
const EBML_ID_CHANNELPOSITIONS
const EBML_ID_EBMLVERSION
const EBML_ID_OUTPUTSAMPLINGFREQUENCY
static EBML2Int($EBMLstring)
const EBML_ID_DOCTYPE
const EBML_ID_DURATION
const EBML_ID_CLUSTER
const EBML_ID_CLUSTERTIMESLICE
const EBML_ID_CODECINFOURL
const EBML_ID_EDITIONFLAGORDERED
const EBML_ID_CLUSTERFRAMENUMBER
const EBML_ID_CONTENTENCODINGS
const EBML_ID_CLUSTERSILENTTRACKNUMBER
const EBML_ID_CUETRACK
const EBML_ID_ATTACHMENTS
static trimNullByte($string)
const EBML_ID_CLUSTERREFERENCEPRIORITY
const EBML_ID_BITDEPTH
const EBML_ID_CONTENTCOMPSETTINGS
const EBML_ID_CHAPPROCESS
const EBML_ID_CHANNELS
EnsureBufferHasEnoughData($min_data=1024)
const EBML_ID_CLUSTERBLOCKGROUP
http://www.matroska.org/technical/specs/index.html
const EBML_ID_PIXELCROPTOP
const EBML_ID_SEGMENTFILENAME
const EBML_ID_TAGTRACKUID
const EBML_ID_MUXINGAPP
static BlockLacingType($lacingtype)
readEBMLelementData($length, $check_buffer=false)
const EBML_ID_CUEREFCLUSTER
const EBML_ID_TRACKTRANSLATEEDITIONUID
const EBML_ID_CHAPTERTRANSLATE
const EBML_ID_TRACKTIMECODESCALE
const EBML_ID_CONTENTCOMPRESSION
const EBML_ID_CHAPTERSEGMENTEDITIONUID
static getDefaultStreamInfo($streams)
fread($bytes)
Definition: getid3.php:1683
const EBML_ID_CHAPPROCESSTIME
const EBML_ID_PIXELCROPBOTTOM
const EBML_ID_TARGETTYPE
const EBML_ID_CLUSTERLACENUMBER
const EBML_ID_CLUSTERPOSITION
const EBML_ID_EBMLMAXIDLENGTH
static TargetTypeValue($target_type)
static CodecIDtoCommonName($codecid)
const EBML_ID_FLAGLACING
const EBML_ID_CHAPTERTRANSLATECODEC
const EBML_ID_TRACKTRANSLATETRACKID
const EBML_ID_MAXCACHE
const EBML_ID_TRACKTRANSLATE
const EBML_ID_STEREOMODE
const EBML_ID_TAGLANGUAGE
const EBML_ID_CHAPTERTRANSLATEEDITIONUID
const EBML_ID_CONTENTSIGKEYID
const EBML_ID_CODECDECODEALL
const EBML_ID_EBMLMAXSIZELENGTH
const EBML_ID_FLAGINTERLACED
const EBML_ID_DISPLAYHEIGHT
const EBML_ID_CHAPTERATOM
const EBML_ID_FILEDESCRIPTION
const EBML_ID_TAGATTACHMENTUID
const EBML_ID_CHAPPROCESSDATA
$i
Definition: disco.tpl.php:19
const EBML_ID_FLAGDEFAULT
const EBML_ID_CLUSTERBLOCKVIRTUAL
const EBML_ID_CUEBLOCKNUMBER
const EBML_ID_CLUSTERBLOCKADDITIONID
const EBML_ID_FILEUID
const EBML_ID_FILENAME
const EBML_ID_EBMLREADVERSION
unhandledElement($type, $line, $element)
const EBML_ID_CLUSTERREFERENCEBLOCK
const EBML_ID_DOCTYPEVERSION
const EBML_ID_PIXELWIDTH
const EBML_ID_PREVFILENAME
const EBML_ID_TRACKTYPE
const EBML_ID_TIMECODESCALE
const EBML_ID_WRITINGAPP
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
const EBML_ID_SEGMENTFAMILY
ExtractCommentsSimpleTag($SimpleTagArray)
const EBML_ID_TRACKOFFSET
const EBML_ID_CLUSTERBLOCKADDITIONS
const EBML_ID_DOCTYPEREADVERSION
const EBML_ID_CUECODECSTATE
const EBML_ID_CUEREFCODECSTATE
const EBML_ID_CHAPTERTRACK
const EBML_ID_PIXELCROPLEFT
const EBML_ID_CONTENTENCRYPTION
$info
Definition: index.php:5
const EBML_ID_SEEKID
const EBML_ID_FILEMIMETYPE
$key
Definition: croninfo.php:18
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:263
const EBML_ID_CONTENTENCALGO
const EBML_ID_MAXBLOCKADDITIONID
const EBML_ID_CLUSTERBLOCKDURATION
const EBML_ID_TAGDEFAULT
const EBML_ID_DATEUTC
const EBML_ID_EDITIONUID
const EBML_ID_CHAPTERS
getID3() by James Heinrich info@getid3.org //
const EBML_ID_CLUSTERTIMECODE
const EBML_ID_OLDSTEREOMODE
const EBML_ID_CLUSTERDELAY
const EBML_ID_CHAPSTRING
$data
Definition: bench.php:6
const EBML_ID_TRACKENTRY
const EBML_ID_CLUSTERBLOCKMORE