36 {
37 $info = &$this->getid3->info;
38
39
40
41
42 $info[
'fileformat'] =
'vqf';
43 $info[
'audio'][
'dataformat'] =
'vqf';
44 $info[
'audio'][
'bitrate_mode'] =
'cbr';
45 $info[
'audio'][
'lossless'] =
false;
46
47
48 $info[
'vqf'][
'raw'] = array();
49 $thisfile_vqf = &
$info[
'vqf'];
50 $thisfile_vqf_raw = &$thisfile_vqf['raw'];
51
52 fseek($this->getid3->fp,
$info[
'avdataoffset'], SEEK_SET);
53 $VQFheaderData =
fread($this->getid3->fp, 16);
54
55 $offset = 0;
56 $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
57 $magic = 'TWIN';
58 if ($thisfile_vqf_raw['header_tag'] != $magic) {
59 $info[
'error'][] =
'Expecting "'.Helper::PrintHexBytes($magic).
'" at offset '.
$info[
'avdataoffset'].
', found "'.
Helper::PrintHexBytes($thisfile_vqf_raw[
'header_tag']).
'"';
61 unset(
$info[
'fileformat']);
62
63 return false;
64 }
65 $offset += 4;
66 $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
67 $offset += 8;
69 $offset += 4;
70
71 while (
ftell($this->getid3->fp) <
$info[
'avdataend']) {
72
73 $ChunkBaseOffset =
ftell($this->getid3->fp);
74 $chunkoffset = 0;
75 $ChunkData =
fread($this->getid3->fp, 8);
76 $ChunkName = substr($ChunkData, $chunkoffset, 4);
77 if ($ChunkName == 'DATA') {
78 $info[
'avdataoffset'] = $ChunkBaseOffset;
79 break;
80 }
81 $chunkoffset += 4;
83 $chunkoffset += 4;
84 if ($ChunkSize > (
$info[
'avdataend'] -
ftell($this->getid3->fp))) {
85 $info[
'error'][] =
'Invalid chunk size ('.$ChunkSize.
') for chunk "'.$ChunkName.
'" at offset '.$ChunkBaseOffset;
86 break;
87 }
88 if ($ChunkSize > 0) {
89 $ChunkData .=
fread($this->getid3->fp, $ChunkSize);
90 }
91
92 switch ($ChunkName) {
93 case 'COMM':
94
95 $thisfile_vqf['COMM'] = array();
96 $thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
97
99 $chunkoffset += 4;
101 $chunkoffset += 4;
103 $chunkoffset += 4;
105 $chunkoffset += 4;
106
107 $info[
'audio'][
'channels'] = $thisfile_vqf_COMM[
'channel_mode'] + 1;
109 $info[
'audio'][
'bitrate'] = $thisfile_vqf_COMM[
'bitrate'] * 1000;
110 $info[
'audio'][
'encoder_options'] =
'CBR' . ceil(
$info[
'audio'][
'bitrate']/1000);
111
112 if (
$info[
'audio'][
'bitrate'] == 0) {
113 $info[
'error'][] =
'Corrupt VQF file: bitrate_audio == zero';
114
115 return false;
116 }
117 break;
118
119 case 'NAME':
120 case 'AUTH':
121 case '(c) ':
122 case 'FILE':
123 case 'COMT':
124 case 'ALBM':
126 break;
127
128 case 'DSIZ':
130 break;
131
132 default:
133 $info[
'warning'][] =
'Unhandled chunk type "'.$ChunkName.
'" at offset '.$ChunkBaseOffset;
134 break;
135 }
136 }
137
138 $info[
'playtime_seconds'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'audio'][
'bitrate'];
139
140 if (isset($thisfile_vqf[
'DSIZ']) && (($thisfile_vqf[
'DSIZ'] != (
$info[
'avdataend'] -
$info[
'avdataoffset'] - strlen(
'DATA'))))) {
141 switch ($thisfile_vqf['DSIZ']) {
142 case 0:
143 case 1:
144 $info[
'warning'][] =
'Invalid DSIZ value "'.$thisfile_vqf[
'DSIZ'].
'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf[
'DSIZ'] + 1).
'.0';
145 $info[
'audio'][
'encoder'] =
'Ahead Nero';
146 break;
147
148 default:
149 $info[
'warning'][] =
'Probable corrupted file - should be '.$thisfile_vqf[
'DSIZ'].
' bytes, actually '.(
$info[
'avdataend'] -
$info[
'avdataoffset'] - strlen(
'DATA'));
150 break;
151 }
152 }
153
154 return true;
155 }
fseek($bytes, $whence=SEEK_SET)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
VQFchannelFrequencyLookup($frequencyid)
@staticvar array $VQFchannelFrequencyLookup
VQFcommentNiceNameLookup($shortname)
@staticvar array $VQFcommentNiceNameLookup