28 $info = &$this->getid3->info;
31 $StreamMarker = $this->
fread(4);
32 if ($StreamMarker != self::syncword) {
35 $info[
'fileformat'] =
'flac';
36 $info[
'audio'][
'dataformat'] =
'flac';
37 $info[
'audio'][
'bitrate_mode'] =
'vbr';
38 $info[
'audio'][
'lossless'] =
true;
45 $info = &$this->getid3->info;
47 $BlockOffset = $this->
ftell();
48 $BlockHeader = $this->
fread(4);
50 $LastBlockFlag = (bool) ($LBFBT & 0x80);
51 $BlockType = ($LBFBT & 0x7F);
53 $BlockTypeText = self::metaBlockTypeLookup($BlockType);
55 if (($BlockOffset + 4 + $BlockLength) >
$info[
'avdataend']) {
56 $this->
error(
'METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.
') at offset '.$BlockOffset.
' extends beyond end of file');
59 if ($BlockLength < 1) {
60 $this->
error(
'METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.
') at offset '.$BlockOffset.
' is invalid');
64 $info[
'flac'][$BlockTypeText][
'raw'] =
array();
65 $BlockTypeText_raw = &
$info[
'flac'][$BlockTypeText][
'raw'];
67 $BlockTypeText_raw[
'offset'] = $BlockOffset;
68 $BlockTypeText_raw[
'last_meta_block'] = $LastBlockFlag;
69 $BlockTypeText_raw[
'block_type'] = $BlockType;
70 $BlockTypeText_raw[
'block_type_text'] = $BlockTypeText;
71 $BlockTypeText_raw[
'block_length'] = $BlockLength;
72 if ($BlockTypeText_raw[
'block_type'] != 0x06) {
73 $BlockTypeText_raw[
'block_data'] = $this->
fread($BlockLength);
76 switch ($BlockTypeText) {
84 unset(
$info[
'flac'][
'PADDING']);
99 case 'VORBIS_COMMENT':
106 if (!$this->
parseCUESHEET($BlockTypeText_raw[
'block_data'])) {
118 $this->
warning(
'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.
') at offset '.$BlockOffset);
121 unset(
$info[
'flac'][$BlockTypeText][
'raw']);
124 while ($LastBlockFlag ===
false);
127 if (!empty(
$info[
'flac'][
'VORBIS_COMMENT'][
'comments'])) {
128 $info[
'flac'][
'comments'] =
$info[
'flac'][
'VORBIS_COMMENT'][
'comments'];
130 if (!empty(
$info[
'flac'][
'VORBIS_COMMENT'][
'vendor'])) {
131 $info[
'audio'][
'encoder'] = str_replace(
'reference ',
'',
$info[
'flac'][
'VORBIS_COMMENT'][
'vendor']);
136 foreach (
$info[
'flac'][
'PICTURE'] as $entry) {
137 if (!empty($entry[
'data'])) {
138 if (!isset(
$info[
'flac'][
'comments'][
'picture'])) {
139 $info[
'flac'][
'comments'][
'picture'] =
array();
141 $comments_picture_data =
array();
142 foreach (
array(
'data',
'image_mime',
'image_width',
'image_height',
'imagetype',
'picturetype',
'description',
'datalength') as $picture_key) {
143 if (isset($entry[$picture_key])) {
144 $comments_picture_data[$picture_key] = $entry[$picture_key];
147 $info[
'flac'][
'comments'][
'picture'][] = $comments_picture_data;
148 unset($comments_picture_data);
153 if (isset(
$info[
'flac'][
'STREAMINFO'])) {
155 $info[
'flac'][
'compressed_audio_bytes'] =
$info[
'avdataend'] -
$info[
'avdataoffset'];
157 $info[
'flac'][
'uncompressed_audio_bytes'] =
$info[
'flac'][
'STREAMINFO'][
'samples_stream'] *
$info[
'flac'][
'STREAMINFO'][
'channels'] * (
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'] / 8);
158 if (
$info[
'flac'][
'uncompressed_audio_bytes'] == 0) {
159 return $this->
error(
'Corrupt FLAC file: uncompressed_audio_bytes == zero');
161 if (!empty(
$info[
'flac'][
'compressed_audio_bytes'])) {
162 $info[
'flac'][
'compression_ratio'] =
$info[
'flac'][
'compressed_audio_bytes'] /
$info[
'flac'][
'uncompressed_audio_bytes'];
167 if (isset(
$info[
'flac'][
'STREAMINFO'][
'audio_signature'])) {
169 if (
$info[
'flac'][
'STREAMINFO'][
'audio_signature'] === str_repeat(
"\x00", 16)) {
170 $this->
warning(
'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
173 $info[
'md5_data_source'] =
'';
174 $md5 =
$info[
'flac'][
'STREAMINFO'][
'audio_signature'];
175 for (
$i = 0;
$i < strlen($md5);
$i++) {
176 $info[
'md5_data_source'] .= str_pad(dechex(ord($md5[
$i])), 2,
'00', STR_PAD_LEFT);
178 if (!preg_match(
'/^[0-9a-f]{32}$/',
$info[
'md5_data_source'])) {
179 unset(
$info[
'md5_data_source']);
184 if (isset(
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'])) {
185 $info[
'audio'][
'bits_per_sample'] =
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'];
186 if (
$info[
'audio'][
'bits_per_sample'] == 8) {
190 $this->
warning(
'FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file');
198 $info = &$this->getid3->info;
201 $streaminfo = &
$info[
'flac'][
'STREAMINFO'];
214 $streaminfo[
'audio_signature'] = substr($BlockData, 18, 16);
216 if (!empty($streaminfo[
'sample_rate'])) {
218 $info[
'audio'][
'bitrate_mode'] =
'vbr';
219 $info[
'audio'][
'sample_rate'] = $streaminfo[
'sample_rate'];
220 $info[
'audio'][
'channels'] = $streaminfo[
'channels'];
221 $info[
'audio'][
'bits_per_sample'] = $streaminfo[
'bits_per_sample'];
222 $info[
'playtime_seconds'] = $streaminfo[
'samples_stream'] / $streaminfo[
'sample_rate'];
223 if (
$info[
'playtime_seconds'] > 0) {
225 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
228 $this->
warning(
'Cannot determine audio bitrate because total stream size is unknown');
233 return $this->
error(
'Corrupt METAdata block: STREAMINFO');
240 $info = &$this->getid3->info;
243 $info[
'flac'][
'APPLICATION'][$ApplicationID][
'name'] = self::applicationIDLookup($ApplicationID);
244 $info[
'flac'][
'APPLICATION'][$ApplicationID][
'data'] = substr($BlockData, 4);
250 $info = &$this->getid3->info;
253 $BlockLength = strlen($BlockData);
254 $placeholderpattern = str_repeat(
"\xFF", 8);
255 while ($offset < $BlockLength) {
256 $SampleNumberString = substr($BlockData, $offset, 8);
258 if ($SampleNumberString == $placeholderpattern) {
279 $info = &$this->getid3->info;
283 $getid3_ogg->setStringMode($this->data_string);
285 $getid3_ogg->ParseVorbisComments();
286 if (isset(
$info[
'ogg'])) {
287 unset(
$info[
'ogg'][
'comments_raw']);
288 $info[
'flac'][
'VORBIS_COMMENT'] =
$info[
'ogg'];
298 $info = &$this->getid3->info;
300 $info[
'flac'][
'CUESHEET'][
'media_catalog_number'] = trim(substr($BlockData, $offset, 128),
"\0");
312 for ($track = 0; $track <
$info[
'flac'][
'CUESHEET'][
'number_tracks']; $track++) {
318 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'sample_offset'] = $TrackSampleOffset;
320 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'isrc'] = substr($BlockData, $offset, 12);
325 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'flags'][
'is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
326 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'flags'][
'pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
330 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'index_points'] =
getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
333 for (
$index = 0;
$index < $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'index_points'];
$index++) {
341 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'indexes'][$IndexNumber] = $IndexSampleOffset;
353 $info = &$this->getid3->info;
356 $picture[
'picturetype'] = self::pictureTypeLookup($picture[
'typeid']);
360 $picture[
'description'] = $this->
fread($descr_length);
368 if ($picture[
'image_mime'] ==
'-->') {
369 $picture[
'data'] = $this->
fread($picture[
'datalength']);
372 str_replace(
'/',
'_', $picture[
'picturetype']).
'_'.$this->
ftell(),
374 $picture[
'datalength'],
375 $picture[
'image_mime']);
378 $info[
'flac'][
'PICTURE'][] = $picture;
384 static $lookup =
array(
389 4 =>
'VORBIS_COMMENT',
393 return (isset($lookup[$blocktype]) ? $lookup[$blocktype] :
'reserved');
398 static $lookup =
array(
399 0x41544348 =>
'FlacFile',
400 0x42534F4C =>
'beSolo',
401 0x42554753 =>
'Bugs Player',
402 0x43756573 =>
'GoldWave cue points (specification)',
403 0x46696361 =>
'CUE Splitter',
404 0x46746F6C =>
'flac-tools',
405 0x4D4F5442 =>
'MOTB MetaCzar',
406 0x4D505345 =>
'MP3 Stream Editor',
407 0x4D754D4C =>
'MusicML: Music Metadata Language',
408 0x52494646 =>
'Sound Devices RIFF chunk storage',
409 0x5346464C =>
'Sound Font FLAC',
410 0x534F4E59 =>
'Sony Creative Software',
411 0x5351455A =>
'flacsqueeze',
412 0x54745776 =>
'TwistedWave',
413 0x55495453 =>
'UITS Embedding tools',
414 0x61696666 =>
'FLAC AIFF chunk storage',
415 0x696D6167 =>
'flac-image application for storing arbitrary files in APPLICATION metadata blocks',
416 0x7065656D =>
'Parseable Embedded Extensible Metadata (specification)',
417 0x71667374 =>
'QFLAC Studio',
418 0x72696666 =>
'FLAC RIFF chunk storage',
419 0x74756E65 =>
'TagTuner',
420 0x78626174 =>
'XBAT',
421 0x786D6364 =>
'xmcd',
423 return (isset($lookup[$applicationid]) ? $lookup[$applicationid] :
'reserved');
427 static $lookup =
array (
429 1 =>
'32x32 pixels \'file icon\' (PNG only)',
430 2 =>
'Other file icon',
431 3 =>
'Cover (front)',
434 6 =>
'Media (e.g. label side of CD)',
435 7 =>
'Lead artist/lead performer/soloist',
436 8 =>
'Artist/performer',
438 10 =>
'Band/Orchestra',
440 12 =>
'Lyricist/text writer',
441 13 =>
'Recording Location',
442 14 =>
'During recording',
443 15 =>
'During performance',
444 16 =>
'Movie/video screen capture',
445 17 =>
'A bright coloured fish',
446 18 =>
'Illustration',
447 19 =>
'Band/artist logotype',
448 20 =>
'Publisher/Studio logotype',
450 return (isset($lookup[$type_id]) ? $lookup[$type_id] :
'reserved');
parseSEEKTABLE($BlockData)
parseSTREAMINFO($BlockData)
static safe_inc(&$variable, $increment=1)
parseVORBIS_COMMENT($BlockData)
static pictureTypeLookup($type_id)
static applicationIDLookup($applicationid)
static Bin2Dec($binstring, $signed=false)
saveAttachment($name, $offset, $length, $image_mime=null)
static BigEndian2Bin($byteword)
parsePICTURE()
Parse METADATA_BLOCK_PICTURE flac structure and extract attachment External usage: audio...
static IncludeDependency($filename, $sourcefile, $DieOnFailure=false)
parseCUESHEET($BlockData)
static metaBlockTypeLookup($blocktype)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
parseAPPLICATION($BlockData)
Create styles array
The data for the language used.
fseek($bytes, $whence=SEEK_SET)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
http://flac.sourceforge.net/format.html