39 $info = &$this->getid3->info;
44 $StreamMarker = $this->
fread(4);
46 if ($StreamMarker != $magic) {
49 $info[
'fileformat'] =
'flac';
50 $info[
'audio'][
'dataformat'] =
'flac';
51 $info[
'audio'][
'bitrate_mode'] =
'vbr';
52 $info[
'audio'][
'lossless'] =
true;
63 $info = &$this->getid3->info;
65 $BlockOffset = $this->
ftell();
66 $BlockHeader = $this->
fread(4);
70 $BlockTypeText = self::metaBlockTypeLookup($BlockType);
72 if (($BlockOffset + 4 + $BlockLength) >
$info[
'avdataend']) {
73 $this->
error(
'METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.
') at offset '.$BlockOffset.
' extends beyond end of file');
76 if ($BlockLength < 1) {
77 $this->
error(
'METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.
') at offset '.$BlockOffset.
' is invalid');
81 $info[
'flac'][$BlockTypeText][
'raw'] =
array();
82 $BlockTypeText_raw = &
$info[
'flac'][$BlockTypeText][
'raw'];
84 $BlockTypeText_raw[
'offset'] = $BlockOffset;
85 $BlockTypeText_raw[
'last_meta_block'] = $LastBlockFlag;
86 $BlockTypeText_raw[
'block_type'] = $BlockType;
87 $BlockTypeText_raw[
'block_type_text'] = $BlockTypeText;
88 $BlockTypeText_raw[
'block_length'] = $BlockLength;
89 if ($BlockTypeText_raw[
'block_type'] != 0x06) {
90 $BlockTypeText_raw[
'block_data'] = $this->
fread($BlockLength);
93 switch ($BlockTypeText) {
116 case 'VORBIS_COMMENT':
123 if (!$this->
parseCUESHEET($BlockTypeText_raw[
'block_data'])) {
135 $this->
warning(
'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.
') at offset '.$BlockOffset);
138 unset(
$info[
'flac'][$BlockTypeText][
'raw']);
140 }
while ($LastBlockFlag ===
false);
143 if (!empty(
$info[
'flac'][
'VORBIS_COMMENT'][
'comments'])) {
144 $info[
'flac'][
'comments'] =
$info[
'flac'][
'VORBIS_COMMENT'][
'comments'];
146 if (!empty(
$info[
'flac'][
'VORBIS_COMMENT'][
'vendor'])) {
147 $info[
'audio'][
'encoder'] = str_replace(
'reference ',
'',
$info[
'flac'][
'VORBIS_COMMENT'][
'vendor']);
152 foreach (
$info[
'flac'][
'PICTURE'] as $key => $valuearray) {
153 if (!empty($valuearray[
'image_mime']) && !empty($valuearray[
'data'])) {
154 $info[
'flac'][
'comments'][
'picture'][] =
array(
'image_mime' => $valuearray[
'image_mime'],
'data' => $valuearray[
'data']);
155 unset(
$info[
'flac'][
'PICTURE'][$key]);
160 if (isset(
$info[
'flac'][
'STREAMINFO'])) {
162 $info[
'flac'][
'compressed_audio_bytes'] =
$info[
'avdataend'] -
$info[
'avdataoffset'];
164 $info[
'flac'][
'uncompressed_audio_bytes'] =
$info[
'flac'][
'STREAMINFO'][
'samples_stream'] *
$info[
'flac'][
'STREAMINFO'][
'channels'] * (
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'] / 8);
165 if (
$info[
'flac'][
'uncompressed_audio_bytes'] == 0) {
166 return $this->
error(
'Corrupt FLAC file: uncompressed_audio_bytes == zero');
169 $info[
'flac'][
'compression_ratio'] =
$info[
'flac'][
'compressed_audio_bytes'] /
$info[
'flac'][
'uncompressed_audio_bytes'];
174 if (isset(
$info[
'flac'][
'STREAMINFO'][
'audio_signature'])) {
176 if (
$info[
'flac'][
'STREAMINFO'][
'audio_signature'] === str_repeat(
"\x00", 16)) {
177 $this->
warning(
'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
179 $info[
'md5_data_source'] =
'';
180 $md5 =
$info[
'flac'][
'STREAMINFO'][
'audio_signature'];
181 for ($i = 0; $i < strlen($md5); $i++) {
182 $info[
'md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2,
'00', STR_PAD_LEFT);
184 if (!preg_match(
'/^[0-9a-f]{32}$/',
$info[
'md5_data_source'])) {
185 unset(
$info[
'md5_data_source']);
190 if (isset(
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'])) {
191 $info[
'audio'][
'bits_per_sample'] =
$info[
'flac'][
'STREAMINFO'][
'bits_per_sample'];
192 if (
$info[
'audio'][
'bits_per_sample'] == 8) {
196 $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');
210 $info = &$this->getid3->info;
213 $streaminfo = &
$info[
'flac'][
'STREAMINFO'];
222 $streaminfo[
'channels'] =
Helper::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1;
223 $streaminfo[
'bits_per_sample'] =
Helper::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
224 $streaminfo[
'samples_stream'] =
Helper::Bin2Dec(substr($SRCSBSS, 28, 36));
226 $streaminfo[
'audio_signature'] = substr($BlockData, 18, 16);
228 if (!empty($streaminfo[
'sample_rate'])) {
230 $info[
'audio'][
'bitrate_mode'] =
'vbr';
231 $info[
'audio'][
'sample_rate'] = $streaminfo[
'sample_rate'];
232 $info[
'audio'][
'channels'] = $streaminfo[
'channels'];
233 $info[
'audio'][
'bits_per_sample'] = $streaminfo[
'bits_per_sample'];
234 $info[
'playtime_seconds'] = $streaminfo[
'samples_stream'] / $streaminfo[
'sample_rate'];
235 if (
$info[
'playtime_seconds'] > 0) {
237 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
239 $this->
warning(
'Cannot determine audio bitrate because total stream size is unknown');
244 return $this->
error(
'Corrupt METAdata block: STREAMINFO');
257 $info = &$this->getid3->info;
260 $info[
'flac'][
'APPLICATION'][$ApplicationID][
'name'] = self::applicationIDLookup($ApplicationID);
261 $info[
'flac'][
'APPLICATION'][$ApplicationID][
'data'] = substr($BlockData, 4);
273 $info = &$this->getid3->info;
276 $BlockLength = strlen($BlockData);
277 $placeholderpattern = str_repeat(
"\xFF", 8);
278 while ($offset < $BlockLength) {
279 $SampleNumberString = substr($BlockData, $offset, 8);
281 if ($SampleNumberString == $placeholderpattern) {
308 $info = &$this->getid3->info;
310 $getid3_ogg =
new Ogg($this->getid3);
312 $getid3_ogg->data_string_flag =
true;
315 $getid3_ogg->ParseVorbisComments();
316 if (isset(
$info[
'ogg'])) {
317 unset(
$info[
'ogg'][
'comments_raw']);
318 $info[
'flac'][
'VORBIS_COMMENT'] =
$info[
'ogg'];
334 $info = &$this->getid3->info;
336 $info[
'flac'][
'CUESHEET'][
'media_catalog_number'] = trim(substr($BlockData, $offset, 128),
"\0");
348 for ($track = 0; $track <
$info[
'flac'][
'CUESHEET'][
'number_tracks']; $track++) {
354 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'sample_offset'] = $TrackSampleOffset;
356 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'isrc'] = substr($BlockData, $offset, 12);
361 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'flags'][
'is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
362 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'flags'][
'pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
366 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'index_points'] =
Helper::BigEndian2Int(substr($BlockData, $offset, 1));
369 for ($index = 0; $index < $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'index_points']; $index++) {
377 $info[
'flac'][
'CUESHEET'][
'tracks'][$TrackNumber][
'indexes'][$IndexNumber] = $IndexSampleOffset;
391 $info = &$this->getid3->info;
394 $picture[
'type'] = self::pictureTypeLookup($picture[
'typeid']);
398 $picture[
'description'] = $this->
fread($descr_length);
406 if ($picture[
'image_mime'] ==
'-->') {
407 $picture[
'data'] = $this->
fread($data_length);
411 $picture[
'type'].
'_'.$this->
ftell().
'.'.substr($picture[
'image_mime'], 6),
412 $this->
ftell(), $data_length);
415 $info[
'flac'][
'PICTURE'][] = $picture;
428 static $metaBlockTypeLookup =
array();
429 if (empty($metaBlockTypeLookup)) {
430 $metaBlockTypeLookup[0] =
'STREAMINFO';
431 $metaBlockTypeLookup[1] =
'PADDING';
432 $metaBlockTypeLookup[2] =
'APPLICATION';
433 $metaBlockTypeLookup[3] =
'SEEKTABLE';
434 $metaBlockTypeLookup[4] =
'VORBIS_COMMENT';
435 $metaBlockTypeLookup[5] =
'CUESHEET';
436 $metaBlockTypeLookup[6] =
'PICTURE';
439 return (isset($metaBlockTypeLookup[$blocktype]) ? $metaBlockTypeLookup[$blocktype] :
'reserved');
450 static $applicationIDLookup =
array();
451 if (empty($applicationIDLookup)) {
453 $applicationIDLookup[0x46746F6C] =
'flac-tools';
454 $applicationIDLookup[0x46746F6C] =
'Sound Font FLAC';
457 return (isset($applicationIDLookup[$applicationid]) ? $applicationIDLookup[$applicationid] :
'reserved');
468 static $lookup =
array (
470 1 =>
'32x32 pixels \'file icon\' (PNG only)',
471 2 =>
'Other file icon',
472 3 =>
'Cover (front)',
475 6 =>
'Media (e.g. label side of CD)',
476 7 =>
'Lead artist/lead performer/soloist',
477 8 =>
'Artist/performer',
479 10 =>
'Band/Orchestra',
481 12 =>
'Lyricist/text writer',
482 13 =>
'Recording Location',
483 14 =>
'During recording',
484 15 =>
'During performance',
485 16 =>
'Movie/video screen capture',
486 17 =>
'A bright coloured fish',
487 18 =>
'Illustration',
488 19 =>
'Band/artist logotype',
489 20 =>
'Publisher/Studio logotype',
492 return (isset($lookup[$type_id]) ? $lookup[$type_id] :
'reserved');
static BigEndian2Bin($byteword)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
GetId3() by James Heinrich info@getid3.org //.
parseAPPLICATION($BlockData)
static pictureTypeLookup($type_id)
array $lookup
fseek($bytes, $whence=SEEK_SET)
GetId3() by James Heinrich info@getid3.org //.
parseSTREAMINFO($BlockData)
static metaBlockTypeLookup($blocktype)
array $metaBlockTypeLookup
GetId3() by James Heinrich info@getid3.org //.
parseVORBIS_COMMENT($BlockData)
Create styles array
The data for the language used.
parseCUESHEET($BlockData)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
parseSEEKTABLE($BlockData)
static safe_inc(&$variable, $increment=1)
static Bin2Dec($binstring, $signed=false)
static applicationIDLookup($applicationid)
array $applicationIDLookup
saveAttachment(&$ThisFileInfoIndex, $filename, $offset, $length)