[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

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


Generated: Thu Nov 21 01:00:03 2024 Cross-referenced by PHPXref 0.7.1