ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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
18define('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.
19define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
20define('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>.
21define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file.
22define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described.
23define('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.
24define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files.
25define('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.
26define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment.
27define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure.
28define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form.
29define('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).
30define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame.
31define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec.
32define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used.
33define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds).
34define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits).
35define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value.
36define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used.
37define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used.
38define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment.
39define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits).
40define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment.
41define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits).
42define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are:
43define('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.
44define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case).
45define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file.
46define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file.
47define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file.
48define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska).
49define('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.
50define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file.
51define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form.
52define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains.
53define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits).
54define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date.
55define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form.
56define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag.
57define('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.
58define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag.
59define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale).
60define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent.
61define('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.
62define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored.
63define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition.
64define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition.
65define('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).
66define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one.
67define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced.
68define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file.
69define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file.
70define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file.
71define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed.
72define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
73define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
74define('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:
75define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
76define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
77define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
78define('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:
79define('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:
80define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3").
81define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element.
82define('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.
83define('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:
84define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values:
85define('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.
86define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise.
87define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster.
88define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name.
89define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster.
90define('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.
91define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name.
92define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element).
93define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode.
94define('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).
95define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content).
96define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display.
97define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches).
98define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed).
99define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display.
100define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image.
101define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image.
102define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image.
103define('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.
104define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track.
105define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3").
106define('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.
107define('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.
108define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file.
109define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption.
110define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM.
111define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec.
112define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment.
113define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values.
114define('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.
115define('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.
116define('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.
117define('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.
118define('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).
119define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec.
120define('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.
121define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
122define('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.
123define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target.
124define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType).
125define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom.
126define('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).
127define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment.
128define('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.
129define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom.
130define('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.
131define('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.
132define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
133define('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.
134define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption.
135define('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.
136define('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.
137define('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.
138define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID.
139define('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.
140define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters.
141define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment.
142define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits).
143define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter.
144define('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.
145define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec.
146define('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.
147define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix.
148define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques).
149define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment.
150define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display.
151define('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).
152define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom.
153define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info.
154define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference.
155define('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.
156define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description.
157define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply
158define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled).
159define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled).
160define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block.
161define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block.
162define('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).
163define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced.
164define('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.
165define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing.
166define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track.
167define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock.
168define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode.
169define('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.
170define('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.
171define('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.
172define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID).
173define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters.
174define('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.
175define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data.
176define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing.
177define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements.
178define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed).
179define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels.
180define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base.
181define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz.
182define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks).
183define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode.
184define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used.
185define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels.
186define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment.
187define('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.
188define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block).
189define('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.
190define('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).
191define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element.
192define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element.
193define('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).
194define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks.
195define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings.
196define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings.
197define('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.
198define('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.
199define('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.
200define('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.
201define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale).
202define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level.
203define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block.
204define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given.
205define('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.
206define('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.
207define('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 = '';
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
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
599 case EBML_ID_TRACKUID:
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:
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
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
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
656 $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
657 break;
658
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
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:
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
940 $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
941 break;
942
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
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
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
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
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:
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
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:
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}
$size
Definition: RandomTest.php:84
An exception for terminatinating execution or to throw for unit testing.
const ATTACHMENTS_NONE
Definition: getid3.php:118
saveAttachment($name, $offset, $length, $image_mime=null)
Definition: getid3.php:1766
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1711
fread($bytes)
Definition: getid3.php:1683
warning($text)
Definition: getid3.php:1758
error($text)
Definition: getid3.php:1752
static trimNullByte($string)
static IncludeDependency($filename, $sourcefile, $DieOnFailure=false)
static BigEndian2Float($byteword)
Definition: getid3.lib.php:185
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:263
@tutorial http://www.matroska.org/technical/specs/index.html
static CodecIDtoCommonName($codecid)
readEBMLelementData($length, $check_buffer=false)
EnsureBufferHasEnoughData($min_data=1024)
static TargetTypeValue($target_type)
static getDefaultStreamInfo($streams)
static EBML2Int($EBMLstring)
getEBMLelement(&$element, $parent_end, $get_data=false)
static BlockLacingType($lacingtype)
static EBMLdate2unix($EBMLdatestamp)
unhandledElement($type, $line, $element)
ExtractCommentsSimpleTag($SimpleTagArray)
HandleEMBLClusterBlock($element, $block_type, &$info)
static parseWAVEFORMATex($WaveFormatExData)
static ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true)
static fourccLookup($fourcc)
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
$target_type
Definition: goto.php:48
$info
Definition: index.php:5
const EBML_ID_EDITIONUID
const EBML_ID_DOCTYPEREADVERSION
const EBML_ID_EBMLREADVERSION
const EBML_ID_SEGMENTFILENAME
const EBML_ID_TRACKNUMBER
const EBML_ID_FILENAME
const EBML_ID_SAMPLINGFREQUENCY
const EBML_ID_CLUSTERDELAY
const EBML_ID_TAGSTRING
const EBML_ID_TRACKOVERLAY
const EBML_ID_OLDSTEREOMODE
const EBML_ID_FILEUID
const EBML_ID_CONTENTCOMPALGO
const EBML_ID_CLUSTERBLOCKADDITIONS
const EBML_ID_SEEKID
const EBML_ID_SIMPLETAG
const EBML_ID_EBMLMAXIDLENGTH
const EBML_ID_PIXELCROPLEFT
const EBML_ID_TAGEDITIONUID
const EBML_ID_CONTENTSIGNATURE
const EBML_ID_TRACKENTRY
const EBML_ID_DURATION
const EBML_ID_EDITIONFLAGDEFAULT
const EBML_ID_CONTENTCOMPRESSION
const EBML_ID_NEXTUID
const EBML_ID_COLOURSPACE
const EBML_ID_FLAGDEFAULT
const EBML_ID_SEGMENTUID
const EBML_ID_ATTACHEDFILE
const EBML_ID_ATTACHMENTS
const EBML_ID_CLUSTERSILENTTRACKS
const EBML_ID_DOCTYPEVERSION
const EBML_ID_CHAPTERFLAGENABLED
const EBML_ID_CLUSTERSIMPLEBLOCK
const EBML_ID_CUEREFTIME
const EBML_ID_CLUSTERBLOCKVIRTUAL
const EBML_ID_TAGBINARY
const EBML_ID_TRACKTYPE
const EBML_ID_TRACKOFFSET
const EBML_ID_TARGETTYPEVALUE
const EBML_ID_CLUSTERBLOCK
const EBML_ID_CLUSTERBLOCKADDITIONAL
const EBML_ID_CODECPRIVATE
const EBML_ID_TRACKTRANSLATE
const EBML_ID_CHANNELS
const EBML_ID_CHAPTERSEGMENTEDITIONUID
const EBML_ID_CLUSTERFRAMENUMBER
const EBML_ID_CLUSTERCODECSTATE
const EBML_ID_DISPLAYHEIGHT
const EBML_ID_CODECINFOURL
const EBML_ID_CHAPTERTIMESTART
const EBML_ID_CODECDECODEALL
const EBML_ID_CLUSTERENCRYPTEDBLOCK
const EBML_ID_WRITINGAPP
const EBML_ID_TRACKTRANSLATEEDITIONUID
const EBML_ID_CHAPTERSEGMENTUID
const EBML_ID_PIXELHEIGHT
const EBML_ID_CUEREFERENCE
const EBML_ID_FILEREFERRAL
const EBML_ID_CHAPPROCESSCODECID
const EBML_ID_CLUSTERTIMECODE
const EBML_ID_CONTENTENCODINGTYPE
const EBML_ID_CHAPTERTRANSLATECODEC
const EBML_ID_CUEBLOCKNUMBER
const EBML_ID_CUECLUSTERPOSITION
const EBML_ID_CLUSTERBLOCKGROUP
const EBML_ID_TAGLANGUAGE
const EBML_ID_EDITIONFLAGORDERED
const EBML_ID_SEGMENTFAMILY
const EBML_ID_GAMMAVALUE
const EBML_ID_CLUSTERPOSITION
const EBML_ID_CUETRACKPOSITIONS
const EBML_ID_CLUSTERDURATION
const EBML_ID_CLUSTERREFERENCEVIRTUAL
const EBML_ID_DATEUTC
const EBML_ID_CLUSTERSILENTTRACKNUMBER
const EBML_ID_CONTENTENCODING
const EBML_ID_CONTENTENCODINGS
const EBML_ID_CUETRACK
const EBML_ID_CHAPTERFLAGHIDDEN
const EBML_ID_CLUSTERBLOCKADDID
const EBML_ID_NEXTFILENAME
const EBML_ID_TRACKTIMECODESCALE
const EBML_ID_CLUSTERBLOCKDURATION
const EBML_ID_TAGATTACHMENTUID
const EBML_ID_DEFAULTDURATION
const EBML_ID_PIXELCROPBOTTOM
const EBML_ID_CUEREFCLUSTER
const EBML_ID_DISPLAYWIDTH
const EBML_ID_CHAPTERTRACKNUMBER
const EBML_ID_FLAGLACING
const EBML_ID_CLUSTERLACENUMBER
const EBML_ID_CHAPLANGUAGE
const EBML_ID_CLUSTERREFERENCEPRIORITY
const EBML_ID_TRACKTRANSLATETRACKID
const EBML_ID_CHAPPROCESSCOMMAND
const EBML_ID_MUXINGAPP
const EBML_ID_CHAPTERS
getID3() by James Heinrich info@getid3.org //
const EBML_ID_CHAPPROCESS
const EBML_ID_EBMLMAXSIZELENGTH
const EBML_ID_FILEDATA
const EBML_ID_CHAPTERPHYSICALEQUIV
const EBML_ID_CLUSTERPREVSIZE
const EBML_ID_CUECODECSTATE
const EBML_ID_TARGETTYPE
const EBML_ID_CONTENTCOMPSETTINGS
const EBML_ID_PREVFILENAME
const EBML_ID_CONTENTSIGKEYID
const EBML_ID_CHAPPROCESSDATA
const EBML_ID_CHAPSTRING
const EBML_ID_TAGCHAPTERUID
const EBML_ID_CODECDOWNLOADURL
const EBML_ID_MAXBLOCKADDITIONID
const EBML_ID_CONTENTENCALGO
const EBML_ID_CHAPPROCESSTIME
const EBML_ID_SEGMENT
const EBML_ID_TAGNAME
const EBML_ID_FILEMIMETYPE
const EBML_ID_CLUSTERREFERENCEBLOCK
const EBML_ID_EBMLVERSION
const EBML_ID_PIXELCROPRIGHT
const EBML_ID_EDITIONFLAGHIDDEN
const EBML_ID_PREVUID
const EBML_ID_CONTENTENCKEYID
const EBML_ID_DOCTYPE
const EBML_ID_CHAPTERATOM
const EBML_ID_TAGDEFAULT
const EBML_ID_PIXELWIDTH
const EBML_ID_CLUSTERBLOCKMORE
const EBML_ID_ASPECTRATIOTYPE
const EBML_ID_TRACKS
const EBML_ID_PIXELCROPTOP
const EBML_ID_CHAPPROCESSPRIVATE
const EBML_ID_FLAGENABLED
const EBML_ID_MAXCACHE
const EBML_ID_TRACKUID
const EBML_ID_CONTENTENCODINGSCOPE
const EBML_ID_OUTPUTSAMPLINGFREQUENCY
const EBML_ID_CONTENTENCRYPTION
const EBML_ID_CUEREFNUMBER
const EBML_ID_CHANNELPOSITIONS
const EBML_ID_EDITIONENTRY
const EBML_ID_TAGTRACKUID
const EBML_ID_CHAPCOUNTRY
const EBML_ID_TRACKTRANSLATECODEC
const EBML_ID_CLUSTERSLICES
const EBML_ID_CODECSETTINGS
const EBML_ID_CONTENTSIGHASHALGO
const EBML_ID_BITDEPTH
const EBML_ID_MINCACHE
const EBML_ID_STEREOMODE
const EBML_ID_TIMECODESCALE
const EBML_ID_CHAPTERTRANSLATEID
const EBML_ID_LANGUAGE
const EBML_ID_CHAPTERTRANSLATE
const EBML_ID_CHAPTERTRANSLATEEDITIONUID
const EBML_ID_CLUSTER
const EBML_ID_DISPLAYUNIT
const EBML_ID_CUEPOINT
const EBML_ID_CHAPTERTIMEEND
const EBML_ID_CHAPTERDISPLAY
const EBML_ID_FLAGINTERLACED
const EBML_ID_FILEDESCRIPTION
const EBML_ID_FLAGFORCED
const EBML_ID_ATTACHMENTLINK
const EBML_ID_CLUSTERTIMESLICE
const EBML_ID_CODECNAME
const EBML_ID_CONTENTENCODINGORDER
const EBML_ID_CONTENTSIGALGO
const EBML_ID_CHAPTERTRACK
const EBML_ID_CLUSTERBLOCKADDITIONID
const EBML_ID_SEEKHEAD
const EBML_ID_CUEREFCODECSTATE
const EBML_ID_SEEKPOSITION
const EBML_ID_CHAPTERUID
$stream
PHP stream implementation.
$type