angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

module.audio-video.matroska.php (107155B)


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