module.audio-video.flv.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2 of the GPL license, |
  8. // | that is bundled with this package in the file license.txt and is |
  9. // | available through the world-wide-web at the following url: |
  10. // | http://www.gnu.org/copyleft/gpl.html |
  11. // +----------------------------------------------------------------------+
  12. // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
  13. // +----------------------------------------------------------------------+
  14. // | Authors: James Heinrich <info�getid3*org> |
  15. // | Allan Hansen <ah�artemis*dk> |
  16. // +----------------------------------------------------------------------+
  17. // | module.archive.gzip.php |
  18. // | module for analyzing GZIP files |
  19. // | dependencies: NONE |
  20. // +----------------------------------------------------------------------+
  21. // | FLV module by Seth Kaufman <seth�whirl-i.gig*com> |
  22. // | |
  23. // | * version 0.1 (26 June 2005) |
  24. // | |
  25. // | minor modifications by James Heinrich <info�getid3*org> |
  26. // | * version 0.1.1 (15 July 2005) |
  27. // | |
  28. // | Support for On2 VP6 codec and meta information by |
  29. // | Steve Webster <steve.webster�featurecreep*com> |
  30. // | * version 0.2 (22 February 2006) |
  31. // | |
  32. // | Modified to not read entire file into memory |
  33. // | by James Heinrich <info�getid3*org> |
  34. // | * version 0.3 (15 June 2006) |
  35. // | |
  36. // | Modifications by Allan Hansen <ah�artemis*dk> |
  37. // | Adapted module for PHP5 and getID3 2.0.0. |
  38. // +----------------------------------------------------------------------+
  39. //
  40. // $Id: module.audio-video.flv.php,v 1.7 2006/11/10 11:20:12 ah Exp $
  41. /**
  42. * @package chamilo.include.flv
  43. */
  44. /**
  45. * Class
  46. * @package chamilo.include.flv
  47. */
  48. class getid3_flv extends getid3_handler {
  49. const TAG_AUDIO = 8;
  50. const TAG_VIDEO = 9;
  51. const TAG_META = 18;
  52. const VIDEO_H263 = 2;
  53. const VIDEO_SCREEN = 3;
  54. const VIDEO_VP6 = 4;
  55. public function Analyze()
  56. {
  57. $info = &$this->getid3->info;
  58. $info['flv'] = array ();
  59. $info_flv = &$info['flv'];
  60. fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
  61. $flv_data_length = $info['avdataend'] - $info['avdataoffset'];
  62. $flv_header = fread($this->getid3->fp, 5);
  63. $info['fileformat'] = 'flv';
  64. $info_flv['header']['signature'] = substr($flv_header, 0, 3);
  65. $info_flv['header']['version'] = getid3_lib::BigEndian2Int(substr($flv_header, 3, 1));
  66. $type_flags = getid3_lib::BigEndian2Int(substr($flv_header, 4, 1));
  67. $info_flv['header']['hasAudio'] = (bool) ($type_flags & 0x04);
  68. $info_flv['header']['hasVideo'] = (bool) ($type_flags & 0x01);
  69. $frame_size_data_length = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
  70. $flv_header_frame_length = 9;
  71. if ($frame_size_data_length > $flv_header_frame_length) {
  72. fseek($this->getid3->fp, $frame_size_data_length - $flv_header_frame_length, SEEK_CUR);
  73. }
  74. $duration = 0;
  75. while ((ftell($this->getid3->fp) + 1) < $info['avdataend']) {
  76. $this_tag_header = fread($this->getid3->fp, 16);
  77. $previous_tag_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 0, 4));
  78. $tag_type = getid3_lib::BigEndian2Int(substr($this_tag_header, 4, 1));
  79. $data_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 5, 3));
  80. $timestamp = getid3_lib::BigEndian2Int(substr($this_tag_header, 8, 3));
  81. $last_header_byte = getid3_lib::BigEndian2Int(substr($this_tag_header, 15, 1));
  82. $next_offset = ftell($this->getid3->fp) - 1 + $data_length;
  83. switch ($tag_type) {
  84. case getid3_flv::TAG_AUDIO:
  85. if (!isset($info_flv['audio']['audioFormat'])) {
  86. $info_flv['audio']['audioFormat'] = $last_header_byte & 0x07;
  87. $info_flv['audio']['audioRate'] = ($last_header_byte & 0x30) / 0x10;
  88. $info_flv['audio']['audioSampleSize'] = ($last_header_byte & 0x40) / 0x40;
  89. $info_flv['audio']['audioType'] = ($last_header_byte & 0x80) / 0x80;
  90. }
  91. break;
  92. case getid3_flv::TAG_VIDEO:
  93. if (!isset($info_flv['video']['videoCodec'])) {
  94. $info_flv['video']['videoCodec'] = $last_header_byte & 0x07;
  95. $flv_video_header = fread($this->getid3->fp, 11);
  96. if ($info_flv['video']['videoCodec'] != getid3_flv::VIDEO_VP6) {
  97. $picture_size_type = (getid3_lib::BigEndian2Int(substr($flv_video_header, 3, 2))) >> 7;
  98. $picture_size_type = $picture_size_type & 0x0007;
  99. $info_flv['header']['videoSizeType'] = $picture_size_type;
  100. switch ($picture_size_type) {
  101. case 0:
  102. $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 2));
  103. $picture_size_enc <<= 1;
  104. $info['video']['resolution_x'] = ($picture_size_enc & 0xFF00) >> 8;
  105. $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 6, 2));
  106. $picture_size_enc <<= 1;
  107. $info['video']['resolution_y'] = ($picture_size_enc & 0xFF00) >> 8;
  108. break;
  109. case 1:
  110. $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 4));
  111. $picture_size_enc <<= 1;
  112. $info['video']['resolution_x'] = ($picture_size_enc & 0xFFFF0000) >> 16;
  113. $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 7, 4));
  114. $picture_size_enc <<= 1;
  115. $info['video']['resolution_y'] = ($picture_size_enc & 0xFFFF0000) >> 16;
  116. break;
  117. case 2:
  118. $info['video']['resolution_x'] = 352;
  119. $info['video']['resolution_y'] = 288;
  120. break;
  121. case 3:
  122. $info['video']['resolution_x'] = 176;
  123. $info['video']['resolution_y'] = 144;
  124. break;
  125. case 4:
  126. $info['video']['resolution_x'] = 128;
  127. $info['video']['resolution_y'] = 96;
  128. break;
  129. case 5:
  130. $info['video']['resolution_x'] = 320;
  131. $info['video']['resolution_y'] = 240;
  132. break;
  133. case 6:
  134. $info['video']['resolution_x'] = 160;
  135. $info['video']['resolution_y'] = 120;
  136. break;
  137. default:
  138. $info['video']['resolution_x'] = 0;
  139. $info['video']['resolution_y'] = 0;
  140. break;
  141. }
  142. }
  143. }
  144. break;
  145. // Meta tag
  146. case getid3_flv::TAG_META:
  147. fseek($this->getid3->fp, -1, SEEK_CUR);
  148. $reader = new AMFReader(new AMFStream(fread($this->getid3->fp, $data_length)));
  149. $event_name = $reader->readData();
  150. $info['meta'][$event_name] = $reader->readData();
  151. unset($reader);
  152. $info['video']['frame_rate'] = @$info['meta']['onMetaData']['framerate'];
  153. $info['video']['resolution_x'] = @$info['meta']['onMetaData']['width'];
  154. $info['video']['resolution_y'] = @$info['meta']['onMetaData']['height'];
  155. break;
  156. default:
  157. // noop
  158. break;
  159. }
  160. if ($timestamp > $duration) {
  161. $duration = $timestamp;
  162. }
  163. fseek($this->getid3->fp, $next_offset, SEEK_SET);
  164. }
  165. if ($info['playtime_seconds'] = $duration / 1000) {
  166. $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'];
  167. }
  168. if ($info_flv['header']['hasAudio']) {
  169. $info['audio']['codec'] = $this->FLVaudioFormat($info_flv['audio']['audioFormat']);
  170. $info['audio']['sample_rate'] = $this->FLVaudioRate($info_flv['audio']['audioRate']);
  171. $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info_flv['audio']['audioSampleSize']);
  172. $info['audio']['channels'] = $info_flv['audio']['audioType'] + 1; // 0=mono,1=stereo
  173. $info['audio']['lossless'] = ($info_flv['audio']['audioFormat'] ? false : true); // 0=uncompressed
  174. $info['audio']['dataformat'] = 'flv';
  175. }
  176. if (@$info_flv['header']['hasVideo']) {
  177. $info['video']['codec'] = $this->FLVvideoCodec($info_flv['video']['videoCodec']);
  178. $info['video']['dataformat'] = 'flv';
  179. $info['video']['lossless'] = false;
  180. }
  181. return true;
  182. }
  183. public static function FLVaudioFormat($id) {
  184. static $lookup = array(
  185. 0 => 'uncompressed',
  186. 1 => 'ADPCM',
  187. 2 => 'mp3',
  188. 5 => 'Nellymoser 8kHz mono',
  189. 6 => 'Nellymoser',
  190. );
  191. return (@$lookup[$id] ? @$lookup[$id] : false);
  192. }
  193. public static function FLVaudioRate($id) {
  194. static $lookup = array(
  195. 0 => 5500,
  196. 1 => 11025,
  197. 2 => 22050,
  198. 3 => 44100,
  199. );
  200. return (@$lookup[$id] ? @$lookup[$id] : false);
  201. }
  202. public static function FLVaudioBitDepth($id) {
  203. static $lookup = array(
  204. 0 => 8,
  205. 1 => 16,
  206. );
  207. return (@$lookup[$id] ? @$lookup[$id] : false);
  208. }
  209. public static function FLVvideoCodec($id) {
  210. static $lookup = array(
  211. getid3_flv::VIDEO_H263 => 'Sorenson H.263',
  212. getid3_flv::VIDEO_SCREEN => 'Screen video',
  213. getid3_flv::VIDEO_VP6 => 'On2 VP6',
  214. );
  215. return (@$lookup[$id] ? @$lookup[$id] : false);
  216. }
  217. }
  218. class AMFStream
  219. {
  220. public $bytes;
  221. public $pos;
  222. public function AMFStream($bytes) {
  223. $this->bytes = $bytes;
  224. $this->pos = 0;
  225. }
  226. public function readByte() {
  227. return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
  228. }
  229. public function readInt() {
  230. return ($this->readByte() << 8) + $this->readByte();
  231. }
  232. public function readLong() {
  233. return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
  234. }
  235. public function readDouble() {
  236. return getid3_lib::BigEndian2Float($this->read(8));
  237. }
  238. public function readUTF() {
  239. $length = $this->readInt();
  240. return $this->read($length);
  241. }
  242. public function readLongUTF() {
  243. $length = $this->readLong();
  244. return $this->read($length);
  245. }
  246. public function read($length) {
  247. $val = substr($this->bytes, $this->pos, $length);
  248. $this->pos += $length;
  249. return $val;
  250. }
  251. public function peekByte() {
  252. $pos = $this->pos;
  253. $val = $this->readByte();
  254. $this->pos = $pos;
  255. return $val;
  256. }
  257. public function peekInt() {
  258. $pos = $this->pos;
  259. $val = $this->readInt();
  260. $this->pos = $pos;
  261. return $val;
  262. }
  263. public function peekLong() {
  264. $pos = $this->pos;
  265. $val = $this->readLong();
  266. $this->pos = $pos;
  267. return $val;
  268. }
  269. public function peekDouble() {
  270. $pos = $this->pos;
  271. $val = $this->readDouble();
  272. $this->pos = $pos;
  273. return $val;
  274. }
  275. public function peekUTF() {
  276. $pos = $this->pos;
  277. $val = $this->readUTF();
  278. $this->pos = $pos;
  279. return $val;
  280. }
  281. public function peekLongUTF() {
  282. $pos = $this->pos;
  283. $val = $this->readLongUTF();
  284. $this->pos = $pos;
  285. return $val;
  286. }
  287. }
  288. class AMFReader
  289. {
  290. public $stream;
  291. public function __construct($stream) {
  292. $this->stream = $stream;
  293. }
  294. public function readData() {
  295. $value = null;
  296. $type = $this->stream->readByte();
  297. switch($type) {
  298. // Double
  299. case 0:
  300. $value = $this->readDouble();
  301. break;
  302. // Boolean
  303. case 1:
  304. $value = $this->readBoolean();
  305. break;
  306. // String
  307. case 2:
  308. $value = $this->readString();
  309. break;
  310. // Object
  311. case 3:
  312. $value = $this->readObject();
  313. break;
  314. // null
  315. case 6:
  316. return null;
  317. break;
  318. // Mixed array
  319. case 8:
  320. $value = $this->readMixedArray();
  321. break;
  322. // Array
  323. case 10:
  324. $value = $this->readArray();
  325. break;
  326. // Date
  327. case 11:
  328. $value = $this->readDate();
  329. break;
  330. // Long string
  331. case 13:
  332. $value = $this->readLongString();
  333. break;
  334. // XML (handled as string)
  335. case 15:
  336. $value = $this->readXML();
  337. break;
  338. // Typed object (handled as object)
  339. case 16:
  340. $value = $this->readTypedObject();
  341. break;
  342. // Long string
  343. default:
  344. $value = '(unknown or unsupported data type)';
  345. break;
  346. }
  347. return $value;
  348. }
  349. public function readDouble() {
  350. return $this->stream->readDouble();
  351. }
  352. public function readBoolean() {
  353. return $this->stream->readByte() == 1;
  354. }
  355. public function readString() {
  356. return $this->stream->readUTF();
  357. }
  358. public function readObject() {
  359. // Get highest numerical index - ignored
  360. $highestIndex = $this->stream->readLong();
  361. $data = array();
  362. while ($key = $this->stream->readUTF()) {
  363. // Mixed array record ends with empty string (0x00 0x00) and 0x09
  364. if (($key == '') && ($this->stream->peekByte() == 0x09)) {
  365. // Consume byte
  366. $this->stream->readByte();
  367. break;
  368. }
  369. $data[$key] = $this->readData();
  370. }
  371. return $data;
  372. }
  373. public function readMixedArray() {
  374. // Get highest numerical index - ignored
  375. $highestIndex = $this->stream->readLong();
  376. $data = array();
  377. while ($key = $this->stream->readUTF()) {
  378. // Mixed array record ends with empty string (0x00 0x00) and 0x09
  379. if (($key == '') && ($this->stream->peekByte() == 0x09)) {
  380. // Consume byte
  381. $this->stream->readByte();
  382. break;
  383. }
  384. if (is_numeric($key)) {
  385. $key = (float) $key;
  386. }
  387. $data[$key] = $this->readData();
  388. }
  389. return $data;
  390. }
  391. public function readArray() {
  392. $length = $this->stream->readLong();
  393. $data = array();
  394. for ($i = 0; $i < count($length); $i++) {
  395. $data[] = $this->readData();
  396. }
  397. return $data;
  398. }
  399. public function readDate() {
  400. $timestamp = $this->stream->readDouble();
  401. $timezone = $this->stream->readInt();
  402. return $timestamp;
  403. }
  404. public function readLongString() {
  405. return $this->stream->readLongUTF();
  406. }
  407. public function readXML() {
  408. return $this->stream->readLongUTF();
  409. }
  410. public function readTypedObject() {
  411. $className = $this->stream->readUTF();
  412. return $this->readObject();
  413. }
  414. }
  415. ?>