[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-includes/ID3/ -> module.audio-video.matroska.php (source)

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


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu