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