公開方法(Public Methods) | |
| getid3_wavpack (&$fd, &$ThisFileInfo) | |
| WavPackMetablockNameLookup (&$id) | |
定義在 module.audio.wavpack.php 檔案之第 17 行.
|
||||||||||||
|
定義在 module.audio.wavpack.php 檔案之第 20 行. 參考 getid3_lib::IncludeDependency(), getid3_lib::LittleEndian2Int(), n, getid3_riff::ParseRIFF(), getid3_riff::ParseRIFFdata(), getid3_lib::PrintHexBytes(), getid3_riff::RIFFcommentsParse(), 及 WavPackMetablockNameLookup(). 00020 { 00021 00022 fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); 00023 00024 while (true) { 00025 00026 $wavpackheader = fread($fd, 32); 00027 00028 if (ftell($fd) >= $ThisFileInfo['avdataend']) { 00029 break; 00030 } elseif (feof($fd)) { 00031 break; 00032 } elseif ( 00033 (@$ThisFileInfo['wavpack']['blockheader']['total_samples'] > 0) && 00034 (@$ThisFileInfo['wavpack']['blockheader']['block_samples'] > 0) && 00035 (!isset($ThisFileInfo['wavpack']['riff_trailer_size']) || ($ThisFileInfo['wavpack']['riff_trailer_size'] <= 0)) && 00036 ((@$ThisFileInfo['wavpack']['config_flags']['md5_checksum'] === false) || !empty($ThisFileInfo['md5_data_source']))) { 00037 break; 00038 } 00039 00040 $blockheader_offset = ftell($fd) - 32; 00041 $blockheader_magic = substr($wavpackheader, 0, 4); 00042 $blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4)); 00043 00044 if ($blockheader_magic != 'wvpk') { 00045 $ThisFileInfo['error'][] = 'Expecting "wvpk" at offset '.$blockheader_offset.', found "'.$blockheader_magic.'"'; 00046 if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) { 00047 unset($ThisFileInfo['fileformat']); 00048 unset($ThisFileInfo['audio']); 00049 unset($ThisFileInfo['wavpack']); 00050 } 00051 return false; 00052 } 00053 00054 00055 if ((@$ThisFileInfo['wavpack']['blockheader']['block_samples'] <= 0) || 00056 (@$ThisFileInfo['wavpack']['blockheader']['total_samples'] <= 0)) { 00057 // Also, it is possible that the first block might not have 00058 // any samples (block_samples == 0) and in this case you should skip blocks 00059 // until you find one with samples because the other information (like 00060 // total_samples) are not guaranteed to be correct until (block_samples > 0) 00061 00062 // Finally, I have defined a format for files in which the length is not known 00063 // (for example when raw files are created using pipes). In these cases 00064 // total_samples will be -1 and you must seek to the final block to determine 00065 // the total number of samples. 00066 00067 00068 $ThisFileInfo['audio']['dataformat'] = 'wavpack'; 00069 $ThisFileInfo['fileformat'] = 'wavpack'; 00070 $ThisFileInfo['audio']['lossless'] = true; 00071 $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; 00072 00073 $ThisFileInfo['wavpack']['blockheader']['offset'] = $blockheader_offset; 00074 $ThisFileInfo['wavpack']['blockheader']['magic'] = $blockheader_magic; 00075 $ThisFileInfo['wavpack']['blockheader']['size'] = $blockheader_size; 00076 00077 if ($ThisFileInfo['wavpack']['blockheader']['size'] >= 0x100000) { 00078 $ThisFileInfo['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$ThisFileInfo['wavpack']['blockheader']['size'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset']; 00079 if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) { 00080 unset($ThisFileInfo['fileformat']); 00081 unset($ThisFileInfo['audio']); 00082 unset($ThisFileInfo['wavpack']); 00083 } 00084 return false; 00085 } 00086 00087 $ThisFileInfo['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8}); 00088 $ThisFileInfo['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9}); 00089 00090 if (($ThisFileInfo['wavpack']['blockheader']['major_version'] != 4) || 00091 (($ThisFileInfo['wavpack']['blockheader']['minor_version'] < 4) && 00092 ($ThisFileInfo['wavpack']['blockheader']['minor_version'] > 16))) { 00093 $ThisFileInfo['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.$ThisFileInfo['wavpack']['blockheader']['minor_version'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset']; 00094 if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) { 00095 unset($ThisFileInfo['fileformat']); 00096 unset($ThisFileInfo['audio']); 00097 unset($ThisFileInfo['wavpack']); 00098 } 00099 return false; 00100 } 00101 00102 $ThisFileInfo['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused 00103 $ThisFileInfo['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused 00104 $ThisFileInfo['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4)); 00105 $ThisFileInfo['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4)); 00106 $ThisFileInfo['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4)); 00107 $ThisFileInfo['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4)); 00108 $ThisFileInfo['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4)); 00109 00110 $ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000003); 00111 $ThisFileInfo['wavpack']['blockheader']['flags']['mono'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000004); 00112 $ThisFileInfo['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000008); 00113 $ThisFileInfo['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000010); 00114 $ThisFileInfo['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000020); 00115 $ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000040); 00116 $ThisFileInfo['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000080); 00117 $ThisFileInfo['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000100); 00118 $ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000200); 00119 $ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000400); 00120 $ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000800); 00121 $ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00001000); 00122 00123 $ThisFileInfo['audio']['lossless'] = !$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid']; 00124 } 00125 00126 while (!feof($fd) && (ftell($fd) < ($blockheader_offset + $blockheader_size + 8))) { 00127 00128 $metablock = array('offset'=>ftell($fd)); 00129 $metablockheader = fread($fd, 2); 00130 if (feof($fd)) { 00131 break; 00132 } 00133 $metablock['id'] = ord($metablockheader{0}); 00134 $metablock['function_id'] = ($metablock['id'] & 0x3F); 00135 $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']); 00136 00137 // The 0x20 bit in the id of the meta subblocks (which is defined as 00138 // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that 00139 // if a decoder encounters an id that it does not know about, it uses 00140 // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set 00141 // then the decoder simply ignores the metadata, but if it is zero 00142 // then the decoder should quit because it means that an understanding 00143 // of the metadata is required to correctly decode the audio. 00144 $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20); 00145 00146 $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40); 00147 $metablock['large_block'] = (bool) ($metablock['id'] & 0x80); 00148 if ($metablock['large_block']) { 00149 $metablockheader .= fread($fd, 2); 00150 } 00151 $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words 00152 $metablock['data'] = null; 00153 00154 if ($metablock['size'] > 0) { 00155 00156 switch ($metablock['function_id']) { 00157 case 0x21: // ID_RIFF_HEADER 00158 case 0x22: // ID_RIFF_TRAILER 00159 case 0x23: // ID_REPLAY_GAIN 00160 case 0x24: // ID_CUESHEET 00161 case 0x25: // ID_CONFIG_BLOCK 00162 case 0x26: // ID_MD5_CHECKSUM 00163 $metablock['data'] = fread($fd, $metablock['size']); 00164 00165 if ($metablock['padded_data']) { 00166 // padded to the nearest even byte 00167 $metablock['size']--; 00168 $metablock['data'] = substr($metablock['data'], 0, -1); 00169 } 00170 break; 00171 00172 case 0x00: // ID_DUMMY 00173 case 0x01: // ID_ENCODER_INFO 00174 case 0x02: // ID_DECORR_TERMS 00175 case 0x03: // ID_DECORR_WEIGHTS 00176 case 0x04: // ID_DECORR_SAMPLES 00177 case 0x05: // ID_ENTROPY_VARS 00178 case 0x06: // ID_HYBRID_PROFILE 00179 case 0x07: // ID_SHAPING_WEIGHTS 00180 case 0x08: // ID_FLOAT_INFO 00181 case 0x09: // ID_INT32_INFO 00182 case 0x0A: // ID_WV_BITSTREAM 00183 case 0x0B: // ID_WVC_BITSTREAM 00184 case 0x0C: // ID_WVX_BITSTREAM 00185 case 0x0D: // ID_CHANNEL_INFO 00186 fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); 00187 break; 00188 00189 default: 00190 $ThisFileInfo['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset']; 00191 fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); 00192 break; 00193 } 00194 00195 switch ($metablock['function_id']) { 00196 case 0x21: // ID_RIFF_HEADER 00197 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 00198 $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4)); 00199 getid3_riff::ParseRIFFdata($metablock['data'], $ParsedRIFFheader); 00200 $metablock['riff'] = $ParsedRIFFheader['riff']; 00201 $metablock['riff']['original_filesize'] = $original_wav_filesize; 00202 $ThisFileInfo['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; 00203 00204 $ThisFileInfo['audio']['sample_rate'] = $ParsedRIFFheader['riff']['raw']['fmt ']['nSamplesPerSec']; 00205 $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['wavpack']['blockheader']['total_samples'] / $ThisFileInfo['audio']['sample_rate']; 00206 00207 // Safe RIFF header in case there's a RIFF footer later 00208 $metablockRIFFheader = $metablock['data']; 00209 break; 00210 00211 00212 case 0x22: // ID_RIFF_TRAILER 00213 $metablockRIFFfooter = $metablockRIFFheader.$metablock['data']; 00214 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 00215 00216 $ftell_old = ftell($fd); 00217 $startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2); 00218 $ParsedRIFFfooter = array('avdataend'=>$ThisFileInfo['avdataend'], 'fileformat'=>'riff', 'error'=>array(), 'warning'=>array()); 00219 $metablock['riff'] = getid3_riff::ParseRIFF($fd, $startoffset, $startoffset + $metablock['size'], $ParsedRIFFfooter); 00220 fseek($fd, $ftell_old, SEEK_SET); 00221 00222 if (!empty($metablock['riff']['INFO'])) { 00223 getid3_riff::RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']); 00224 $ThisFileInfo['tags']['riff'] = $metablock['comments']; 00225 } 00226 break; 00227 00228 00229 case 0x23: // ID_REPLAY_GAIN 00230 $ThisFileInfo['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; 00231 break; 00232 00233 00234 case 0x24: // ID_CUESHEET 00235 $ThisFileInfo['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; 00236 break; 00237 00238 00239 case 0x25: // ID_CONFIG_BLOCK 00240 $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3)); 00241 00242 $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats 00243 $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode 00244 $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast 00245 $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode 00246 $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet) 00247 $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample 00248 $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping 00249 $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified 00250 $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified 00251 $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source 00252 $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable 00253 $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file 00254 $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression 00255 $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode 00256 $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet) 00257 $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode 00258 $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information) 00259 $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode 00260 $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints 00261 $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature 00262 $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress % 00263 00264 $ThisFileInfo['wavpack']['config_flags'] = $metablock['flags']; 00265 00266 00267 if ($ThisFileInfo['wavpack']['blockheader']['flags']['hybrid']) { 00268 @$ThisFileInfo['audio']['encoder_options'] .= ' -b???'; 00269 } 00270 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : ''); 00271 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : ''); 00272 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : ''); 00273 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : ''); 00274 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : ''); 00275 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : ''); 00276 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : ''); 00277 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : ''); 00278 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : ''); 00279 @$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : ''); 00280 if (@$ThisFileInfo['audio']['encoder_options']) { 00281 $ThisFileInfo['audio']['encoder_options'] = trim(@$ThisFileInfo['audio']['encoder_options']); 00282 } 00283 elseif (isset($ThisFileInfo['audio']['encoder_options'])) { 00284 unset($ThisFileInfo['audio']['encoder_options']); 00285 } 00286 break; 00287 00288 00289 case 0x26: // ID_MD5_CHECKSUM 00290 if (strlen($metablock['data']) == 16) { 00291 $ThisFileInfo['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false)); 00292 } else { 00293 $ThisFileInfo['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes'; 00294 } 00295 break; 00296 00297 00298 case 0x00: // ID_DUMMY 00299 case 0x01: // ID_ENCODER_INFO 00300 case 0x02: // ID_DECORR_TERMS 00301 case 0x03: // ID_DECORR_WEIGHTS 00302 case 0x04: // ID_DECORR_SAMPLES 00303 case 0x05: // ID_ENTROPY_VARS 00304 case 0x06: // ID_HYBRID_PROFILE 00305 case 0x07: // ID_SHAPING_WEIGHTS 00306 case 0x08: // ID_FLOAT_INFO 00307 case 0x09: // ID_INT32_INFO 00308 case 0x0A: // ID_WV_BITSTREAM 00309 case 0x0B: // ID_WVC_BITSTREAM 00310 case 0x0C: // ID_WVX_BITSTREAM 00311 case 0x0D: // ID_CHANNEL_INFO 00312 unset($metablock); 00313 break; 00314 } 00315 00316 } 00317 if (!empty($metablock)) { 00318 $ThisFileInfo['wavpack']['metablocks'][] = $metablock; 00319 } 00320 00321 } 00322 00323 } 00324 00325 $ThisFileInfo['audio']['encoder'] = 'WavPack v'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.str_pad($ThisFileInfo['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT); 00326 $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8; 00327 $ThisFileInfo['audio']['channels'] = ($ThisFileInfo['wavpack']['blockheader']['flags']['mono'] ? 1 : 2); 00328 00329 if (@$ThisFileInfo['playtime_seconds']) { 00330 00331 $ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds']; 00332 00333 } else { 00334 00335 $ThisFileInfo['audio']['dataformat'] = 'wvc'; 00336 00337 } 00338 00339 return true; 00340 }
|
|
|
定義在 module.audio.wavpack.php 檔案之第 343 行. 被參考於 getid3_wavpack(). 00343 { 00344 static $WavPackMetablockNameLookup = array( 00345 0x00 => 'Dummy', 00346 0x01 => 'Encoder Info', 00347 0x02 => 'Decorrelation Terms', 00348 0x03 => 'Decorrelation Weights', 00349 0x04 => 'Decorrelation Samples', 00350 0x05 => 'Entropy Variables', 00351 0x06 => 'Hybrid Profile', 00352 0x07 => 'Shaping Weights', 00353 0x08 => 'Float Info', 00354 0x09 => 'Int32 Info', 00355 0x0A => 'WV Bitstream', 00356 0x0B => 'WVC Bitstream', 00357 0x0C => 'WVX Bitstream', 00358 0x0D => 'Channel Info', 00359 0x21 => 'RIFF header', 00360 0x22 => 'RIFF trailer', 00361 0x23 => 'Replay Gain', 00362 0x24 => 'Cuesheet', 00363 0x25 => 'Config Block', 00364 0x26 => 'MD5 Checksum', 00365 ); 00366 return (@$WavPackMetablockNameLookup[$id]); 00367 }
|