getid3_flv

The WordPress Core getid3 flv class.

Defined (1)

The class is defined in the following location(s).

/wp-includes/ID3/module.audio-video.flv.php  
  1. class getid3_flv extends getid3_handler { 
  2.  
  3. const magic = 'FLV'; 
  4.  
  5. public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration 
  6.  
  7. public function Analyze() { 
  8. $info = &$this->getid3->info; 
  9.  
  10. $this->fseek($info['avdataoffset']); 
  11.  
  12. $FLVdataLength = $info['avdataend'] - $info['avdataoffset']; 
  13. $FLVheader = $this->fread(5); 
  14.  
  15. $info['fileformat'] = 'flv'; 
  16. $info['flv']['header']['signature'] = substr($FLVheader, 0, 3); 
  17. $info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1)); 
  18. $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1)); 
  19.  
  20. if ($info['flv']['header']['signature'] != self::magic) { 
  21. $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"'; 
  22. unset($info['flv'], $info['fileformat']); 
  23. return false; 
  24.  
  25. $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04); 
  26. $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01); 
  27.  
  28. $FrameSizeDataLength = getid3_lib::BigEndian2Int($this->fread(4)); 
  29. $FLVheaderFrameLength = 9; 
  30. if ($FrameSizeDataLength > $FLVheaderFrameLength) { 
  31. $this->fseek($FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR); 
  32. $Duration = 0; 
  33. $found_video = false; 
  34. $found_audio = false; 
  35. $found_meta = false; 
  36. $found_valid_meta_playtime = false; 
  37. $tagParseCount = 0; 
  38. $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0); 
  39. $flv_framecount = &$info['flv']['framecount']; 
  40. while ((($this->ftell() + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) { 
  41. $ThisTagHeader = $this->fread(16); 
  42.  
  43. $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4)); 
  44. $TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1)); 
  45. $DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3)); 
  46. $Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3)); 
  47. $LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1)); 
  48. $NextOffset = $this->ftell() - 1 + $DataLength; 
  49. if ($Timestamp > $Duration) { 
  50. $Duration = $Timestamp; 
  51.  
  52. $flv_framecount['total']++; 
  53. switch ($TagType) { 
  54. case GETID3_FLV_TAG_AUDIO: 
  55. $flv_framecount['audio']++; 
  56. if (!$found_audio) { 
  57. $found_audio = true; 
  58. $info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F; 
  59. $info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03; 
  60. $info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01; 
  61. $info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01; 
  62. break; 
  63.  
  64. case GETID3_FLV_TAG_VIDEO: 
  65. $flv_framecount['video']++; 
  66. if (!$found_video) { 
  67. $found_video = true; 
  68. $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07; 
  69.  
  70. $FLVvideoHeader = $this->fread(11); 
  71.  
  72. if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) { 
  73. // this code block contributed by: moysevichgmail*com 
  74.  
  75. $AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1)); 
  76. if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) { 
  77. // read AVCDecoderConfigurationRecord 
  78. $configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1)); 
  79. $AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1)); 
  80. $profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1)); 
  81. $lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1)); 
  82. $numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1)); 
  83.  
  84. if (($numOfSequenceParameterSets & 0x1F) != 0) { 
  85. // there is at least one SequenceParameterSet 
  86. // read size of the first SequenceParameterSet 
  87. //$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2)); 
  88. $spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2)); 
  89. // read the first SequenceParameterSet 
  90. $sps = $this->fread($spsSize); 
  91. if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red 
  92. $spsReader = new AVCSequenceParameterSetReader($sps); 
  93. $spsReader->readData(); 
  94. $info['video']['resolution_x'] = $spsReader->getWidth(); 
  95. $info['video']['resolution_y'] = $spsReader->getHeight(); 
  96. // end: moysevichgmail*com 
  97.  
  98. } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) { 
  99.  
  100. $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7; 
  101. $PictureSizeType = $PictureSizeType & 0x0007; 
  102. $info['flv']['header']['videoSizeType'] = $PictureSizeType; 
  103. switch ($PictureSizeType) { 
  104. case 0: 
  105. //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)); 
  106. //$PictureSizeEnc <<= 1; 
  107. //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8; 
  108. //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2)); 
  109. //$PictureSizeEnc <<= 1; 
  110. //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8; 
  111.  
  112. $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2)) >> 7; 
  113. $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)) >> 7; 
  114. $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF; 
  115. $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF; 
  116. break; 
  117.  
  118. case 1: 
  119. $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3)) >> 7; 
  120. $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3)) >> 7; 
  121. $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF; 
  122. $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF; 
  123. break; 
  124.  
  125. case 2: 
  126. $info['video']['resolution_x'] = 352; 
  127. $info['video']['resolution_y'] = 288; 
  128. break; 
  129.  
  130. case 3: 
  131. $info['video']['resolution_x'] = 176; 
  132. $info['video']['resolution_y'] = 144; 
  133. break; 
  134.  
  135. case 4: 
  136. $info['video']['resolution_x'] = 128; 
  137. $info['video']['resolution_y'] = 96; 
  138. break; 
  139.  
  140. case 5: 
  141. $info['video']['resolution_x'] = 320; 
  142. $info['video']['resolution_y'] = 240; 
  143. break; 
  144.  
  145. case 6: 
  146. $info['video']['resolution_x'] = 160; 
  147. $info['video']['resolution_y'] = 120; 
  148. break; 
  149.  
  150. default: 
  151. $info['video']['resolution_x'] = 0; 
  152. $info['video']['resolution_y'] = 0; 
  153. break; 
  154.  
  155.  
  156. } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_VP6FLV_ALPHA) { 
  157.  
  158. /** contributed by schouwerwougmail*com */ 
  159. if (!isset($info['video']['resolution_x'])) { // only when meta data isn't set 
  160. $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2)); 
  161. $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 2)); 
  162. $info['video']['resolution_x'] = ($PictureSizeEnc['x'] & 0xFF) << 3; 
  163. $info['video']['resolution_y'] = ($PictureSizeEnc['y'] & 0xFF) << 3; 
  164. /** end schouwerwougmail*com */ 
  165.  
  166. if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) { 
  167. $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y']; 
  168. break; 
  169.  
  170. // Meta tag 
  171. case GETID3_FLV_TAG_META: 
  172. if (!$found_meta) { 
  173. $found_meta = true; 
  174. $this->fseek(-1, SEEK_CUR); 
  175. $datachunk = $this->fread($DataLength); 
  176. $AMFstream = new AMFStream($datachunk); 
  177. $reader = new AMFReader($AMFstream); 
  178. $eventName = $reader->readData(); 
  179. $info['flv']['meta'][$eventName] = $reader->readData(); 
  180. unset($reader); 
  181.  
  182. $copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate'); 
  183. foreach ($copykeys as $sourcekey => $destkey) { 
  184. if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) { 
  185. switch ($sourcekey) { 
  186. case 'width': 
  187. case 'height': 
  188. $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey])); 
  189. break; 
  190. case 'audiodatarate': 
  191. $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000)); 
  192. break; 
  193. case 'videodatarate': 
  194. case 'frame_rate': 
  195. default: 
  196. $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey]; 
  197. break; 
  198. if (!empty($info['flv']['meta']['onMetaData']['duration'])) { 
  199. $found_valid_meta_playtime = true; 
  200. break; 
  201.  
  202. default: 
  203. // noop 
  204. break; 
  205. $this->fseek($NextOffset); 
  206.  
  207. $info['playtime_seconds'] = $Duration / 1000; 
  208. if ($info['playtime_seconds'] > 0) { 
  209. $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 
  210.  
  211. if ($info['flv']['header']['hasAudio']) { 
  212. $info['audio']['codec'] = self::audioFormatLookup($info['flv']['audio']['audioFormat']); 
  213. $info['audio']['sample_rate'] = self::audioRateLookup($info['flv']['audio']['audioRate']); 
  214. $info['audio']['bits_per_sample'] = self::audioBitDepthLookup($info['flv']['audio']['audioSampleSize']); 
  215.  
  216. $info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono, 1=stereo 
  217. $info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed 
  218. $info['audio']['dataformat'] = 'flv'; 
  219. if (!empty($info['flv']['header']['hasVideo'])) { 
  220. $info['video']['codec'] = self::videoCodecLookup($info['flv']['video']['videoCodec']); 
  221. $info['video']['dataformat'] = 'flv'; 
  222. $info['video']['lossless'] = false; 
  223.  
  224. // Set information from meta 
  225. if (!empty($info['flv']['meta']['onMetaData']['duration'])) { 
  226. $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration']; 
  227. $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 
  228. if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) { 
  229. $info['audio']['codec'] = self::audioFormatLookup($info['flv']['meta']['onMetaData']['audiocodecid']); 
  230. if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) { 
  231. $info['video']['codec'] = self::videoCodecLookup($info['flv']['meta']['onMetaData']['videocodecid']); 
  232. return true; 
  233.  
  234.  
  235. public static function audioFormatLookup($id) { 
  236. static $lookup = array( 
  237. 0 => 'Linear PCM, platform endian',  
  238. 1 => 'ADPCM',  
  239. 2 => 'mp3',  
  240. 3 => 'Linear PCM, little endian',  
  241. 4 => 'Nellymoser 16kHz mono',  
  242. 5 => 'Nellymoser 8kHz mono',  
  243. 6 => 'Nellymoser',  
  244. 7 => 'G.711A-law logarithmic PCM',  
  245. 8 => 'G.711 mu-law logarithmic PCM',  
  246. 9 => 'reserved',  
  247. 10 => 'AAC',  
  248. 11 => 'Speex',  
  249. 12 => false, // unknown? 
  250. 13 => false, // unknown? 
  251. 14 => 'mp3 8kHz',  
  252. 15 => 'Device-specific sound',  
  253. ); 
  254. return (isset($lookup[$id]) ? $lookup[$id] : false); 
  255.  
  256. public static function audioRateLookup($id) { 
  257. static $lookup = array( 
  258. 0 => 5500,  
  259. 1 => 11025,  
  260. 2 => 22050,  
  261. 3 => 44100,  
  262. ); 
  263. return (isset($lookup[$id]) ? $lookup[$id] : false); 
  264.  
  265. public static function audioBitDepthLookup($id) { 
  266. static $lookup = array( 
  267. 0 => 8,  
  268. 1 => 16,  
  269. ); 
  270. return (isset($lookup[$id]) ? $lookup[$id] : false); 
  271.  
  272. public static function videoCodecLookup($id) { 
  273. static $lookup = array( 
  274. GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',  
  275. GETID3_FLV_VIDEO_SCREEN => 'Screen video',  
  276. GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',  
  277. GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',  
  278. GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',  
  279. GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',  
  280. ); 
  281. return (isset($lookup[$id]) ? $lookup[$id] : false);