ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
module.audio.shorten.php
Go to the documentation of this file.
1 <?php
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
7 // See readme.txt for more details //
9 // //
10 // module.audio.shorten.php //
11 // module for analyzing Shorten Audio files //
12 // dependencies: NONE //
13 // ///
15 
16 
18 {
19 
20  function getid3_shorten(&$fd, &$ThisFileInfo) {
21 
22  fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
23 
24  $ShortenHeader = fread($fd, 8);
25  if (substr($ShortenHeader, 0, 4) != 'ajkg') {
26  $ThisFileInfo['error'][] = 'Expecting "ajkg" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($ShortenHeader, 0, 4).'"';
27  return false;
28  }
29  $ThisFileInfo['fileformat'] = 'shn';
30  $ThisFileInfo['audio']['dataformat'] = 'shn';
31  $ThisFileInfo['audio']['lossless'] = true;
32  $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
33 
34  $ThisFileInfo['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1));
35 
36  fseek($fd, $ThisFileInfo['avdataend'] - 12, SEEK_SET);
37  $SeekTableSignatureTest = fread($fd, 12);
38  $ThisFileInfo['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
39  if ($ThisFileInfo['shn']['seektable']['present']) {
40  $ThisFileInfo['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
41  $ThisFileInfo['shn']['seektable']['offset'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['shn']['seektable']['length'];
42  fseek($fd, $ThisFileInfo['shn']['seektable']['offset'], SEEK_SET);
43  $SeekTableMagic = fread($fd, 4);
44  if ($SeekTableMagic != 'SEEK') {
45 
46  $ThisFileInfo['error'][] = 'Expecting "SEEK" at offset '.$ThisFileInfo['shn']['seektable']['offset'].', found "'.$SeekTableMagic.'"';
47  return false;
48 
49  } else {
50 
51  // typedef struct tag_TSeekEntry
52  // {
53  // unsigned long SampleNumber;
54  // unsigned long SHNFileByteOffset;
55  // unsigned long SHNLastBufferReadPosition;
56  // unsigned short SHNByteGet;
57  // unsigned short SHNBufferOffset;
58  // unsigned short SHNFileBitOffset;
59  // unsigned long SHNGBuffer;
60  // unsigned short SHNBitShift;
61  // long CBuf0[3];
62  // long CBuf1[3];
63  // long Offset0[4];
64  // long Offset1[4];
65  // }TSeekEntry;
66 
67  $SeekTableData = fread($fd, $ThisFileInfo['shn']['seektable']['length'] - 16);
68  $ThisFileInfo['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80);
69  //$ThisFileInfo['shn']['seektable']['entries'] = array();
70  //$SeekTableOffset = 0;
71  //for ($i = 0; $i < $ThisFileInfo['shn']['seektable']['entry_count']; $i++) {
72  // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
73  // $SeekTableOffset += 4;
74  // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
75  // $SeekTableOffset += 4;
76  // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
77  // $SeekTableOffset += 4;
78  // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
79  // $SeekTableOffset += 2;
80  // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
81  // $SeekTableOffset += 2;
82  // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
83  // $SeekTableOffset += 2;
84  // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
85  // $SeekTableOffset += 4;
86  // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
87  // $SeekTableOffset += 2;
88  // for ($j = 0; $j < 3; $j++) {
89  // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
90  // $SeekTableOffset += 4;
91  // }
92  // for ($j = 0; $j < 3; $j++) {
93  // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
94  // $SeekTableOffset += 4;
95  // }
96  // for ($j = 0; $j < 4; $j++) {
97  // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
98  // $SeekTableOffset += 4;
99  // }
100  // for ($j = 0; $j < 4; $j++) {
101  // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
102  // $SeekTableOffset += 4;
103  // }
104  //
105  // $ThisFileInfo['shn']['seektable']['entries'][] = $SeekTableEntry;
106  //}
107 
108  }
109 
110  }
111 
112  if ((bool) ini_get('safe_mode')) {
113  $ThisFileInfo['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files';
114  return false;
115  }
116 
117  if (GETID3_OS_ISWINDOWS) {
118 
119  $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
120  foreach ($RequiredFiles as $required_file) {
121  if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
122  $ThisFileInfo['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist';
123  return false;
124  }
125  }
126  $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$ThisFileInfo['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 44';
127  $commandline = str_replace('/', '\\', $commandline);
128 
129  } else {
130 
131  static $shorten_present;
132  if (!isset($shorten_present)) {
133  $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
134  }
135  if (!$shorten_present) {
136  $ThisFileInfo['error'][] = 'shorten binary was not found in path or /usr/local/bin';
137  return false;
138  }
139  $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($ThisFileInfo['filenamepath']).' - | head -c 44';
140 
141  }
142 
143  $output = `$commandline`;
144 
145  if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
146 
147  getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
148 
149  $DecodedWAVFORMATEX = getid3_riff::RIFFparseWAVEFORMATex(substr($output, 20, 16));
150  $ThisFileInfo['audio']['channels'] = $DecodedWAVFORMATEX['channels'];
151  $ThisFileInfo['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample'];
152  $ThisFileInfo['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate'];
153 
154  if (substr($output, 36, 4) == 'data') {
155 
156  $ThisFileInfo['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 40, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec'];
157 
158  } else {
159 
160  $ThisFileInfo['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime';
161  return false;
162 
163  }
164 
165  $ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds']) * 8;
166 
167  } else {
168 
169  $ThisFileInfo['error'][] = 'shorten failed to decode file to WAV for parsing';
170  return false;
171 
172  }
173 
174  return true;
175  }
176 
177 }
178 
179 ?>