wp/wp-includes/ID3/module.audio-video.riff.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
     1 <?php
     1 <?php
     2 /////////////////////////////////////////////////////////////////
     2 /////////////////////////////////////////////////////////////////
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     4 //  available at http://getid3.sourceforge.net                 //
     4 //  available at http://getid3.sourceforge.net                 //
     5 //            or http://www.getid3.org                         //
     5 //            or http://www.getid3.org                         //
       
     6 //          also https://github.com/JamesHeinrich/getID3       //
     6 /////////////////////////////////////////////////////////////////
     7 /////////////////////////////////////////////////////////////////
     7 // See readme.txt for more details                             //
     8 // See readme.txt for more details                             //
     8 /////////////////////////////////////////////////////////////////
     9 /////////////////////////////////////////////////////////////////
     9 //                                                             //
    10 //                                                             //
    10 // module.audio-video.riff.php                                 //
    11 // module.audio-video.riff.php                                 //
    24 
    25 
    25 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
    26 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
    26 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
    27 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
    27 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
    28 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
    28 
    29 
    29 class getid3_riff extends getid3_handler
    30 class getid3_riff extends getid3_handler {
    30 {
    31 
       
    32 	protected $container = 'riff'; // default
    31 
    33 
    32 	public function Analyze() {
    34 	public function Analyze() {
    33 		$info = &$this->getid3->info;
    35 		$info = &$this->getid3->info;
    34 
    36 
    35 		// initialize these values to an empty array, otherwise they default to NULL
    37 		// initialize these values to an empty array, otherwise they default to NULL
    56 		$RIFFsubtype = substr($RIFFheader, 8, 4);
    58 		$RIFFsubtype = substr($RIFFheader, 8, 4);
    57 
    59 
    58 		switch ($RIFFtype) {
    60 		switch ($RIFFtype) {
    59 
    61 
    60 			case 'FORM':  // AIFF, AIFC
    62 			case 'FORM':  // AIFF, AIFC
    61 				$info['fileformat']   = 'aiff';
    63 				//$info['fileformat']   = 'aiff';
       
    64 				$this->container = 'aiff';
    62 				$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
    65 				$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
    63 				$thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
    66 				$thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
    64 				break;
    67 				break;
    65 
    68 
    66 			case 'RIFF':  // AVI, WAV, etc
    69 			case 'RIFF':  // AVI, WAV, etc
    67 			case 'SDSS':  // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
    70 			case 'SDSS':  // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
    68 			case 'RMP3':  // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
    71 			case 'RMP3':  // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
    69 				$info['fileformat']   = 'riff';
    72 				//$info['fileformat']   = 'riff';
       
    73 				$this->container = 'riff';
    70 				$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
    74 				$thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
    71 				if ($RIFFsubtype == 'RMP3') {
    75 				if ($RIFFsubtype == 'RMP3') {
    72 					// RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
    76 					// RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
    73 					$RIFFsubtype = 'WAVE';
    77 					$RIFFsubtype = 'WAVE';
    74 				}
    78 				}
    75 				$thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
    79 				if ($RIFFsubtype != 'AMV ') {
       
    80 					// AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
       
    81 					// Handled separately in ParseRIFFAMV()
       
    82 					$thisfile_riff[$RIFFsubtype]  = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
       
    83 				}
    76 				if (($info['avdataend'] - $info['filesize']) == 1) {
    84 				if (($info['avdataend'] - $info['filesize']) == 1) {
    77 					// LiteWave appears to incorrectly *not* pad actual output file
    85 					// LiteWave appears to incorrectly *not* pad actual output file
    78 					// to nearest WORD boundary so may appear to be short by one
    86 					// to nearest WORD boundary so may appear to be short by one
    79 					// byte, in which case - skip warning
    87 					// byte, in which case - skip warning
    80 					$info['avdataend'] = $info['filesize'];
    88 					$info['avdataend'] = $info['filesize'];
   108 					$chunkdata['offset'] = $nextRIFFoffset + 8;
   116 					$chunkdata['offset'] = $nextRIFFoffset + 8;
   109 					$chunkdata['size']   = $nextRIFFsize;
   117 					$chunkdata['size']   = $nextRIFFsize;
   110 					$nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
   118 					$nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
   111 
   119 
   112 					switch ($nextRIFFheaderID) {
   120 					switch ($nextRIFFheaderID) {
   113 
       
   114 						case 'RIFF':
   121 						case 'RIFF':
   115 							$chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
   122 							$chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
   116 
       
   117 							if (!isset($thisfile_riff[$nextRIFFtype])) {
   123 							if (!isset($thisfile_riff[$nextRIFFtype])) {
   118 								$thisfile_riff[$nextRIFFtype] = array();
   124 								$thisfile_riff[$nextRIFFtype] = array();
   119 							}
   125 							}
   120 							$thisfile_riff[$nextRIFFtype][] = $chunkdata;
   126 							$thisfile_riff[$nextRIFFtype][] = $chunkdata;
       
   127 							break;
       
   128 
       
   129 						case 'AMV ':
       
   130 							unset($info['riff']);
       
   131 							$info['amv'] = $this->ParseRIFFAMV($chunkdata['offset'] + 4, $nextRIFFoffset);
   121 							break;
   132 							break;
   122 
   133 
   123 						case 'JUNK':
   134 						case 'JUNK':
   124 							// ignore
   135 							// ignore
   125 							$thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
   136 							$thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
   150 				}
   161 				}
   151 				break;
   162 				break;
   152 
   163 
   153 			default:
   164 			default:
   154 				$this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
   165 				$this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
   155 				unset($info['fileformat']);
   166 				//unset($info['fileformat']);
   156 				return false;
   167 				return false;
   157 		}
   168 		}
   158 
   169 
   159 		$streamindex = 0;
   170 		$streamindex = 0;
   160 		switch ($RIFFsubtype) {
   171 		switch ($RIFFsubtype) {
       
   172 
       
   173 			// http://en.wikipedia.org/wiki/Wav
   161 			case 'WAVE':
   174 			case 'WAVE':
       
   175 				$info['fileformat'] = 'wav';
       
   176 
   162 				if (empty($thisfile_audio['bitrate_mode'])) {
   177 				if (empty($thisfile_audio['bitrate_mode'])) {
   163 					$thisfile_audio['bitrate_mode'] = 'cbr';
   178 					$thisfile_audio['bitrate_mode'] = 'cbr';
   164 				}
   179 				}
   165 				if (empty($thisfile_audio_dataformat)) {
   180 				if (empty($thisfile_audio_dataformat)) {
   166 					$thisfile_audio_dataformat = 'wav';
   181 					$thisfile_audio_dataformat = 'wav';
   586 						$thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
   601 						$thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
   587 					}
   602 					}
   588 				}
   603 				}
   589 				break;
   604 				break;
   590 
   605 
       
   606 			// http://en.wikipedia.org/wiki/Audio_Video_Interleave
   591 			case 'AVI ':
   607 			case 'AVI ':
       
   608 				$info['fileformat'] = 'avi';
       
   609 				$info['mime_type']  = 'video/avi';
       
   610 
   592 				$thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
   611 				$thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
   593 				$thisfile_video['dataformat']   = 'avi';
   612 				$thisfile_video['dataformat']   = 'avi';
   594 				$info['mime_type']      = 'video/avi';
       
   595 
   613 
   596 				if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
   614 				if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
   597 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
   615 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
   598 					if (isset($thisfile_riff['AVIX'])) {
   616 					if (isset($thisfile_riff['AVIX'])) {
   599 						$info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
   617 						$info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
   823 													break;
   841 													break;
   824 											}
   842 											}
   825 
   843 
   826 											switch ($strhfccType) {
   844 											switch ($strhfccType) {
   827 												case 'vids':
   845 												case 'vids':
   828 													$thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff'));
   846 													$thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($this->container == 'riff'));
   829 													$thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
   847 													$thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
   830 
   848 
   831 													if ($thisfile_riff_video_current['codec'] == 'DV') {
   849 													if ($thisfile_riff_video_current['codec'] == 'DV') {
   832 														$thisfile_riff_video_current['dv_type'] = 2;
   850 														$thisfile_riff_video_current['dv_type'] = 2;
   833 													}
   851 													}
   873 						}
   891 						}
   874 					}
   892 					}
   875 				}
   893 				}
   876 				break;
   894 				break;
   877 
   895 
       
   896 
       
   897 			case 'AMV ':
       
   898 				$info['fileformat'] = 'amv';
       
   899 				$info['mime_type']  = 'video/amv';
       
   900 
       
   901 				$thisfile_video['bitrate_mode']    = 'vbr'; // it's MJPEG, presumably contant-quality encoding, thereby VBR
       
   902 				$thisfile_video['dataformat']      = 'mjpeg';
       
   903 				$thisfile_video['codec']           = 'mjpeg';
       
   904 				$thisfile_video['lossless']        = false;
       
   905 				$thisfile_video['bits_per_sample'] = 24;
       
   906 
       
   907 				$thisfile_audio['dataformat']   = 'adpcm';
       
   908 				$thisfile_audio['lossless']     = false;
       
   909 				break;
       
   910 
       
   911 
       
   912 			// http://en.wikipedia.org/wiki/CD-DA
   878 			case 'CDDA':
   913 			case 'CDDA':
   879 				$thisfile_audio['bitrate_mode'] = 'cbr';
   914 				$info['fileformat'] = 'cda';
       
   915 			    unset($info['mime_type']);
       
   916 
   880 				$thisfile_audio_dataformat      = 'cda';
   917 				$thisfile_audio_dataformat      = 'cda';
   881 				$thisfile_audio['lossless']     = true;
       
   882 				unset($info['mime_type']);
       
   883 
   918 
   884 				$info['avdataoffset'] = 44;
   919 				$info['avdataoffset'] = 44;
   885 
   920 
   886 				if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
   921 				if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
   887 					// shortcut
   922 					// shortcut
   899 					$thisfile_riff_CDDA_fmt_0['playtime_seconds']     = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
   934 					$thisfile_riff_CDDA_fmt_0['playtime_seconds']     = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
   900 					$info['comments']['track']                = $thisfile_riff_CDDA_fmt_0['track_num'];
   935 					$info['comments']['track']                = $thisfile_riff_CDDA_fmt_0['track_num'];
   901 					$info['playtime_seconds']                 = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
   936 					$info['playtime_seconds']                 = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
   902 
   937 
   903 					// hardcoded data for CD-audio
   938 					// hardcoded data for CD-audio
       
   939 					$thisfile_audio['lossless']        = true;
   904 					$thisfile_audio['sample_rate']     = 44100;
   940 					$thisfile_audio['sample_rate']     = 44100;
   905 					$thisfile_audio['channels']        = 2;
   941 					$thisfile_audio['channels']        = 2;
   906 					$thisfile_audio['bits_per_sample'] = 16;
   942 					$thisfile_audio['bits_per_sample'] = 16;
   907 					$thisfile_audio['bitrate']         = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
   943 					$thisfile_audio['bitrate']         = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
   908 					$thisfile_audio['bitrate_mode']    = 'cbr';
   944 					$thisfile_audio['bitrate_mode']    = 'cbr';
   909 				}
   945 				}
   910 				break;
   946 				break;
   911 
   947 
   912 
   948             // http://en.wikipedia.org/wiki/AIFF
   913 			case 'AIFF':
   949 			case 'AIFF':
   914 			case 'AIFC':
   950 			case 'AIFC':
       
   951 				$info['fileformat'] = 'aiff';
       
   952 				$info['mime_type']  = 'audio/x-aiff';
       
   953 
   915 				$thisfile_audio['bitrate_mode'] = 'cbr';
   954 				$thisfile_audio['bitrate_mode'] = 'cbr';
   916 				$thisfile_audio_dataformat      = 'aiff';
   955 				$thisfile_audio_dataformat      = 'aiff';
   917 				$thisfile_audio['lossless']     = true;
   956 				$thisfile_audio['lossless']     = true;
   918 				$info['mime_type']      = 'audio/x-aiff';
       
   919 
   957 
   920 				if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
   958 				if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
   921 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
   959 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
   922 					$info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
   960 					$info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
   923 					if ($info['avdataend'] > $info['filesize']) {
   961 					if ($info['avdataend'] > $info['filesize']) {
  1026 					unset($getid3_temp, $getid3_id3v2);
  1064 					unset($getid3_temp, $getid3_id3v2);
  1027 				}
  1065 				}
  1028 */
  1066 */
  1029 				break;
  1067 				break;
  1030 
  1068 
       
  1069 			// http://en.wikipedia.org/wiki/8SVX
  1031 			case '8SVX':
  1070 			case '8SVX':
       
  1071 				$info['fileformat'] = '8svx';
       
  1072 				$info['mime_type']  = 'audio/8svx';
       
  1073 
  1032 				$thisfile_audio['bitrate_mode']    = 'cbr';
  1074 				$thisfile_audio['bitrate_mode']    = 'cbr';
  1033 				$thisfile_audio_dataformat         = '8svx';
  1075 				$thisfile_audio_dataformat         = '8svx';
  1034 				$thisfile_audio['bits_per_sample'] = 8;
  1076 				$thisfile_audio['bits_per_sample'] = 8;
  1035 				$thisfile_audio['channels']        = 1; // overridden below, if need be
  1077 				$thisfile_audio['channels']        = 1; // overridden below, if need be
  1036 				$info['mime_type']                = 'audio/x-aiff';
       
  1037 
  1078 
  1038 				if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
  1079 				if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
  1039 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
  1080 					$info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
  1040 					$info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
  1081 					$info['avdataend']    = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
  1041 					if ($info['avdataend'] > $info['filesize']) {
  1082 					if ($info['avdataend'] > $info['filesize']) {
  1106 				if (!empty($thisfile_audio['bitrate'])) {
  1147 				if (!empty($thisfile_audio['bitrate'])) {
  1107 					$info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
  1148 					$info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
  1108 				}
  1149 				}
  1109 				break;
  1150 				break;
  1110 
  1151 
  1111 
       
  1112 			case 'CDXA':
  1152 			case 'CDXA':
  1113 				$info['mime_type'] = 'video/mpeg';
  1153 				$info['fileformat'] = 'vcd'; // Asume Video CD
       
  1154 				$info['mime_type']  = 'video/mpeg';
       
  1155 
  1114 				if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
  1156 				if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
  1115 					if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) {
  1157 					getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
  1116 						$getid3_temp = new getID3();
  1158 
  1117 						$getid3_temp->openfile($this->getid3->filename);
  1159 					$getid3_temp = new getID3();
  1118 						$getid3_mpeg = new getid3_mpeg($getid3_temp);
  1160 					$getid3_temp->openfile($this->getid3->filename);
  1119 						$getid3_mpeg->Analyze();
  1161 					$getid3_mpeg = new getid3_mpeg($getid3_temp);
  1120 						if (empty($getid3_temp->info['error'])) {
  1162 					$getid3_mpeg->Analyze();
  1121 							$info['audio']   = $getid3_temp->info['audio'];
  1163 					if (empty($getid3_temp->info['error'])) {
  1122 							$info['video']   = $getid3_temp->info['video'];
  1164 						$info['audio']   = $getid3_temp->info['audio'];
  1123 							$info['mpeg']    = $getid3_temp->info['mpeg'];
  1165 						$info['video']   = $getid3_temp->info['video'];
  1124 							$info['warning'] = $getid3_temp->info['warning'];
  1166 						$info['mpeg']    = $getid3_temp->info['mpeg'];
  1125 						}
  1167 						$info['warning'] = $getid3_temp->info['warning'];
  1126 						unset($getid3_temp, $getid3_mpeg);
  1168 					}
  1127 					}
  1169 					unset($getid3_temp, $getid3_mpeg);
  1128 				}
  1170 				}
  1129 				break;
  1171 				break;
  1130 
  1172 
  1131 
  1173 
  1132 			default:
  1174 			default:
  1133 				$info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
  1175 				$info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
  1134 				unset($info['fileformat']);
  1176 				//unset($info['fileformat']);
  1135 				break;
       
  1136 		}
  1177 		}
  1137 
  1178 
  1138 		switch ($RIFFsubtype) {
  1179 		switch ($RIFFsubtype) {
  1139 			case 'WAVE':
  1180 			case 'WAVE':
  1140 			case 'AIFF':
  1181 			case 'AIFF':
  1148 					}
  1189 					}
  1149 				}
  1190 				}
  1150 
  1191 
  1151 				if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
  1192 				if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
  1152 					getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
  1193 					getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
       
  1194 
  1153 					$getid3_temp = new getID3();
  1195 					$getid3_temp = new getID3();
  1154 					$getid3_temp->openfile($this->getid3->filename);
  1196 					$getid3_temp->openfile($this->getid3->filename);
  1155 					$getid3_id3v2 = new getid3_id3v2($getid3_temp);
  1197 					$getid3_id3v2 = new getid3_id3v2($getid3_temp);
  1156 					$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
  1198 					$getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
  1157 					if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
  1199 					if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
  1276 		}
  1318 		}
  1277 
  1319 
  1278 		return true;
  1320 		return true;
  1279 	}
  1321 	}
  1280 
  1322 
       
  1323 	public function ParseRIFFAMV($startoffset, $maxoffset) {
       
  1324 		// AMV files are RIFF-AVI files with parts of the spec deliberately broken, such as chunk size fields hardcoded to zero (because players known in hardware that these fields are always a certain size
       
  1325 
       
  1326 		// https://code.google.com/p/amv-codec-tools/wiki/AmvDocumentation
       
  1327 		//typedef struct _amvmainheader {
       
  1328 		//FOURCC fcc; // 'amvh'
       
  1329 		//DWORD cb;
       
  1330 		//DWORD dwMicroSecPerFrame;
       
  1331 		//BYTE reserve[28];
       
  1332 		//DWORD dwWidth;
       
  1333 		//DWORD dwHeight;
       
  1334 		//DWORD dwSpeed;
       
  1335 		//DWORD reserve0;
       
  1336 		//DWORD reserve1;
       
  1337 		//BYTE bTimeSec;
       
  1338 		//BYTE bTimeMin;
       
  1339 		//WORD wTimeHour;
       
  1340 		//} AMVMAINHEADER;
       
  1341 
       
  1342 		$info = &$this->getid3->info;
       
  1343 		$RIFFchunk = false;
       
  1344 
       
  1345 		try {
       
  1346 
       
  1347 			$this->fseek($startoffset);
       
  1348 			$maxoffset = min($maxoffset, $info['avdataend']);
       
  1349 			$AMVheader = $this->fread(284);
       
  1350 			if (substr($AMVheader,   0,  8) != 'hdrlamvh') {
       
  1351 				throw new Exception('expecting "hdrlamv" at offset '.($startoffset +   0).', found "'.substr($AMVheader,   0, 8).'"');
       
  1352 			}
       
  1353 			if (substr($AMVheader,   8,  4) != "\x38\x00\x00\x00") { // "amvh" chunk size, hardcoded to 0x38 = 56 bytes
       
  1354 				throw new Exception('expecting "0x38000000" at offset '.($startoffset +   8).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,   8, 4)).'"');
       
  1355 			}
       
  1356 			$RIFFchunk = array();
       
  1357 			$RIFFchunk['amvh']['us_per_frame']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  12,  4));
       
  1358 			$RIFFchunk['amvh']['reserved28']     =                              substr($AMVheader,  16, 28);  // null? reserved?
       
  1359 			$RIFFchunk['amvh']['resolution_x']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  44,  4));
       
  1360 			$RIFFchunk['amvh']['resolution_y']   = getid3_lib::LittleEndian2Int(substr($AMVheader,  48,  4));
       
  1361 			$RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  52,  4));
       
  1362 			$RIFFchunk['amvh']['reserved0']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  56,  4)); // 1? reserved?
       
  1363 			$RIFFchunk['amvh']['reserved1']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  60,  4)); // 0? reserved?
       
  1364 			$RIFFchunk['amvh']['runtime_sec']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  64,  1));
       
  1365 			$RIFFchunk['amvh']['runtime_min']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  65,  1));
       
  1366 			$RIFFchunk['amvh']['runtime_hrs']    = getid3_lib::LittleEndian2Int(substr($AMVheader,  66,  2));
       
  1367 
       
  1368 			$info['video']['frame_rate']   = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
       
  1369 			$info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
       
  1370 			$info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
       
  1371 			$info['playtime_seconds']      = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
       
  1372 
       
  1373 			// the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded
       
  1374 
       
  1375 			if (substr($AMVheader,  68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
       
  1376 				throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset +  68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader,  68, 20)).'"');
       
  1377 			}
       
  1378 			// followed by 56 bytes of null: substr($AMVheader,  88, 56) -> 144
       
  1379 			if (substr($AMVheader, 144,  8) != 'strf'."\x24\x00\x00\x00") {
       
  1380 				throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144,  8)).'"');
       
  1381 			}
       
  1382 			// followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
       
  1383 
       
  1384 			if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
       
  1385 				throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
       
  1386 			}
       
  1387 			// followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
       
  1388 			if (substr($AMVheader, 256,  8) != 'strf'."\x14\x00\x00\x00") {
       
  1389 				throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256,  8)).'"');
       
  1390 			}
       
  1391 			// followed by 20 bytes of a modified WAVEFORMATEX:
       
  1392 			// typedef struct {
       
  1393 			// WORD wFormatTag;       //(Fixme: this is equal to PCM's 0x01 format code)
       
  1394 			// WORD nChannels;        //(Fixme: this is always 1)
       
  1395 			// DWORD nSamplesPerSec;  //(Fixme: for all known sample files this is equal to 22050)
       
  1396 			// DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
       
  1397 			// WORD nBlockAlign;      //(Fixme: this seems to be 2 in AMV files, is this correct ?)
       
  1398 			// WORD wBitsPerSample;   //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
       
  1399 			// WORD cbSize;           //(Fixme: this seems to be 0 in AMV files)
       
  1400 			// WORD reserved;
       
  1401 			// } WAVEFORMATEX;
       
  1402 			$RIFFchunk['strf']['wformattag']      = getid3_lib::LittleEndian2Int(substr($AMVheader,  264,  2));
       
  1403 			$RIFFchunk['strf']['nchannels']       = getid3_lib::LittleEndian2Int(substr($AMVheader,  266,  2));
       
  1404 			$RIFFchunk['strf']['nsamplespersec']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  268,  4));
       
  1405 			$RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader,  272,  4));
       
  1406 			$RIFFchunk['strf']['nblockalign']     = getid3_lib::LittleEndian2Int(substr($AMVheader,  276,  2));
       
  1407 			$RIFFchunk['strf']['wbitspersample']  = getid3_lib::LittleEndian2Int(substr($AMVheader,  278,  2));
       
  1408 			$RIFFchunk['strf']['cbsize']          = getid3_lib::LittleEndian2Int(substr($AMVheader,  280,  2));
       
  1409 			$RIFFchunk['strf']['reserved']        = getid3_lib::LittleEndian2Int(substr($AMVheader,  282,  2));
       
  1410 
       
  1411 
       
  1412 			$info['audio']['lossless']        = false;
       
  1413 			$info['audio']['sample_rate']     = $RIFFchunk['strf']['nsamplespersec'];
       
  1414 			$info['audio']['channels']        = $RIFFchunk['strf']['nchannels'];
       
  1415 			$info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
       
  1416 			$info['audio']['bitrate']         = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
       
  1417 			$info['audio']['bitrate_mode']    = 'cbr';
       
  1418 
       
  1419 
       
  1420 		} catch (getid3_exception $e) {
       
  1421 			if ($e->getCode() == 10) {
       
  1422 				$this->warning('RIFFAMV parser: '.$e->getMessage());
       
  1423 			} else {
       
  1424 				throw $e;
       
  1425 			}
       
  1426 		}
       
  1427 
       
  1428 		return $RIFFchunk;
       
  1429 	}
       
  1430 
       
  1431 
  1281 	public function ParseRIFF($startoffset, $maxoffset) {
  1432 	public function ParseRIFF($startoffset, $maxoffset) {
  1282 		$info = &$this->getid3->info;
  1433 		$info = &$this->getid3->info;
  1283 
  1434 
  1284 		$RIFFchunk = false;
  1435 		$RIFFchunk = false;
  1285 		$FoundAllChunksWeNeed = false;
  1436 		$FoundAllChunksWeNeed = false;
  1327 										if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
  1478 										if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
  1328 											$getid3_temp = new getID3();
  1479 											$getid3_temp = new getID3();
  1329 											$getid3_temp->openfile($this->getid3->filename);
  1480 											$getid3_temp->openfile($this->getid3->filename);
  1330 											$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
  1481 											$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
  1331 											$getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
  1482 											$getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
  1332 											$getid3_mp3 = new getid3_mp3($getid3_temp);
  1483 											$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
  1333 											$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
  1484 											$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
  1334 											if (isset($getid3_temp->info['mpeg']['audio'])) {
  1485 											if (isset($getid3_temp->info['mpeg']['audio'])) {
  1335 												$info['mpeg']['audio']         = $getid3_temp->info['mpeg']['audio'];
  1486 												$info['mpeg']['audio']         = $getid3_temp->info['mpeg']['audio'];
  1336 												$info['audio']                 = $getid3_temp->info['audio'];
  1487 												$info['audio']                 = $getid3_temp->info['audio'];
  1337 												$info['audio']['dataformat']   = 'mp'.$info['mpeg']['audio']['layer'];
  1488 												$info['audio']['dataformat']   = 'mp'.$info['mpeg']['audio']['layer'];
  1410 									if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
  1561 									if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
  1411 										$getid3_temp = new getID3();
  1562 										$getid3_temp = new getID3();
  1412 										$getid3_temp->openfile($this->getid3->filename);
  1563 										$getid3_temp->openfile($this->getid3->filename);
  1413 										$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  1564 										$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
  1414 										$getid3_temp->info['avdataend']    = $info['avdataend'];
  1565 										$getid3_temp->info['avdataend']    = $info['avdataend'];
  1415 										$getid3_mp3 = new getid3_mp3($getid3_temp);
  1566 										$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
  1416 										$getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
  1567 										$getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
  1417 										if (empty($getid3_temp->info['error'])) {
  1568 										if (empty($getid3_temp->info['error'])) {
  1418 											$info['audio'] = $getid3_temp->info['audio'];
  1569 											$info['audio'] = $getid3_temp->info['audio'];
  1419 											$info['mpeg']  = $getid3_temp->info['mpeg'];
  1570 											$info['mpeg']  = $getid3_temp->info['mpeg'];
  1420 										}
  1571 										}
  2424 
  2575 
  2425 		return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
  2576 		return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
  2426 	}
  2577 	}
  2427 
  2578 
  2428 	private function EitherEndian2Int($byteword, $signed=false) {
  2579 	private function EitherEndian2Int($byteword, $signed=false) {
  2429 		if ($this->getid3->info['fileformat'] == 'riff') {
  2580 		if ($this->container == 'riff') {
  2430 			return getid3_lib::LittleEndian2Int($byteword, $signed);
  2581 			return getid3_lib::LittleEndian2Int($byteword, $signed);
  2431 		}
  2582 		}
  2432 		return getid3_lib::BigEndian2Int($byteword, false, $signed);
  2583 		return getid3_lib::BigEndian2Int($byteword, false, $signed);
  2433 	}
  2584 	}
  2434 
  2585