Ejemplo n.º 1
0
function getOnlyMPEGaudioInfo($fd, &$MP3fileInfo, $audiodataoffset)
{
    // looks for synch, decodes MPEG audio header
    // you may call this function directly if you don't need any ID3 info
    fseek($fd, $audiodataoffset);
    $header = '';
    $SynchSeekOffset = 0;
    while (!isset($MP3fileInfo['fileformat']) || $MP3fileInfo['fileformat'] == '' || $MP3fileInfo['fileformat'] == 'id3') {
        if ($SynchSeekOffset > strlen($header) - 8192 && !feof($fd)) {
            if ($SynchSeekOffset > FREAD_BUFFER_SIZE * 4) {
                // if a synch's not found within the first 64k bytes, then give up
                $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch within the first ' . FREAD_BUFFER_SIZE * 4 . ' bytes';
                if (isset($MP3fileInfo['bitrate'])) {
                    unset($MP3fileInfo['bitrate']);
                }
                if (isset($MP3fileInfo['mpeg']['audio'])) {
                    unset($MP3fileInfo['mpeg']['audio']);
                }
                if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                    unset($MP3fileInfo['mpeg']);
                }
                return FALSE;
            } else {
                if ($header .= fread($fd, FREAD_BUFFER_SIZE)) {
                    // great
                } else {
                    $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                    if (isset($MP3fileInfo['bitrate'])) {
                        unset($MP3fileInfo['bitrate']);
                    }
                    if (isset($MP3fileInfo['mpeg']['audio'])) {
                        unset($MP3fileInfo['mpeg']['audio']);
                    }
                    if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                        unset($MP3fileInfo['mpeg']);
                    }
                    return FALSE;
                }
            }
        }
        if (ord($header[$SynchSeekOffset]) == 0xff && substr(BigEndian2Bin(substr($header, $SynchSeekOffset, 2)), 0, 11) == '11111111111') {
            // synch detected
            if (decodeMPEGaudioHeader($fd, $audiodataoffset + $SynchSeekOffset, $MP3fileInfo, TRUE)) {
                $MP3fileInfo['audiodataoffset'] = $audiodataoffset + $SynchSeekOffset;
                $MP3fileInfo['fileformat'] = 'mp3';
                break;
                // exit for() and while()
            }
        }
        if (!isset($MP3fileInfo['fileformat']) || $MP3fileInfo['fileformat'] == '' || $MP3fileInfo['fileformat'] == 'id3') {
            $SynchSeekOffset++;
            if ($audiodataoffset + $SynchSeekOffset >= $MP3fileInfo['filesize']) {
                // end of file
                $MP3fileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                if (isset($MP3fileInfo['bitrate'])) {
                    unset($MP3fileInfo['bitrate']);
                }
                if (isset($MP3fileInfo['mpeg']['audio'])) {
                    unset($MP3fileInfo['mpeg']['audio']);
                }
                if (isset($MP3fileInfo['mpeg']) && (!is_array($MP3fileInfo['mpeg']) || count($MP3fileInfo['mpeg']) == 0)) {
                    unset($MP3fileInfo['mpeg']);
                }
                return FALSE;
            }
        }
    }
    return TRUE;
}
Ejemplo n.º 2
0
function getOnlyMPEGaudioInfo($fd, &$ThisFileInfo, $avdataoffset, $BitrateHistogram = false)
{
    // looks for synch, decodes MPEG audio header
    fseek($fd, $avdataoffset, SEEK_SET);
    $header = '';
    $SynchSeekOffset = 0;
    if (!defined('CONST_FF')) {
        define('CONST_FF', chr(0xff));
        define('CONST_E0', chr(0xe0));
    }
    static $MPEGaudioVersionLookup;
    static $MPEGaudioLayerLookup;
    static $MPEGaudioBitrateLookup;
    if (empty($MPEGaudioVersionLookup)) {
        $MPEGaudioVersionLookup = MPEGaudioVersionArray();
        $MPEGaudioLayerLookup = MPEGaudioLayerArray();
        $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
    }
    $header_len = strlen($header) - round(FREAD_BUFFER_SIZE / 2);
    while (true) {
        if ($SynchSeekOffset > $header_len && $avdataoffset + $SynchSeekOffset < $ThisFileInfo['avdataend'] && !feof($fd)) {
            if ($SynchSeekOffset > 131072) {
                // if a synch's not found within the first 128k bytes, then give up
                $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch within the first 131072 bytes';
                if (isset($ThisFileInfo['audio']['bitrate'])) {
                    unset($ThisFileInfo['audio']['bitrate']);
                }
                if (isset($ThisFileInfo['mpeg']['audio'])) {
                    unset($ThisFileInfo['mpeg']['audio']);
                }
                if (isset($ThisFileInfo['mpeg']) && (!is_array($ThisFileInfo['mpeg']) || count($ThisFileInfo['mpeg']) == 0)) {
                    unset($ThisFileInfo['mpeg']);
                }
                return false;
            } elseif ($header .= fread($fd, FREAD_BUFFER_SIZE)) {
                // great
                $header_len = strlen($header) - round(FREAD_BUFFER_SIZE / 2);
            } else {
                $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                if (isset($ThisFileInfo['audio']['bitrate'])) {
                    unset($ThisFileInfo['audio']['bitrate']);
                }
                if (isset($ThisFileInfo['mpeg']['audio'])) {
                    unset($ThisFileInfo['mpeg']['audio']);
                }
                if (isset($ThisFileInfo['mpeg']) && (!is_array($ThisFileInfo['mpeg']) || count($ThisFileInfo['mpeg']) == 0)) {
                    unset($ThisFileInfo['mpeg']);
                }
                return false;
            }
        }
        if ($SynchSeekOffset + 1 >= strlen($header)) {
            $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
            return false;
        }
        if ($header[$SynchSeekOffset] == CONST_FF && $header[$SynchSeekOffset + 1] > CONST_E0) {
            // synch detected
            if (!isset($FirstFrameThisfileInfo) && !isset($ThisFileInfo['mpeg']['audio'])) {
                $FirstFrameThisfileInfo = $ThisFileInfo;
                $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
                if (!decodeMPEGaudioHeader($fd, $avdataoffset + $SynchSeekOffset, $FirstFrameThisfileInfo, false)) {
                    // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
                    // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
                    unset($FirstFrameThisfileInfo);
                }
            }
            $dummy = $ThisFileInfo;
            // only overwrite real data if valid header found
            if (decodeMPEGaudioHeader($fd, $avdataoffset + $SynchSeekOffset, $dummy, true)) {
                $ThisFileInfo = $dummy;
                $ThisFileInfo['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
                switch ($ThisFileInfo['fileformat']) {
                    case '':
                    case 'id3':
                    case 'ape':
                    case 'mp3':
                        $ThisFileInfo['fileformat'] = 'mp3';
                        $ThisFileInfo['audio']['dataformat'] = 'mp3';
                }
                if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && $FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') {
                    if (!CloseMatch($ThisFileInfo['audio']['bitrate'], $FirstFrameThisfileInfo['audio']['bitrate'], 1)) {
                        // If there is garbage data between a valid VBR header frame and a sequence
                        // of valid MPEG-audio frames the VBR data is no longer discarded.
                        $ThisFileInfo = $FirstFrameThisfileInfo;
                        $ThisFileInfo['avdataoffset'] = $FirstFrameAVDataOffset;
                        $ThisFileInfo['fileformat'] = 'mp3';
                        $ThisFileInfo['audio']['dataformat'] = 'mp3';
                        $dummy = $ThisFileInfo;
                        unset($dummy['mpeg']['audio']);
                        $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
                        $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset;
                        if (decodeMPEGaudioHeader($fd, $GarbageOffsetEnd, $dummy, true, true)) {
                            $ThisFileInfo = $dummy;
                            $ThisFileInfo['avdataoffset'] = $GarbageOffsetEnd;
                            $ThisFileInfo['warning'] .= "\n" . 'apparently-valid VBR header not used because could not find ' . MPEG_VALID_CHECK_FRAMES . ' consecutive MPEG-audio frames immediately after VBR header (garbage data for ' . ($GarbageOffsetEnd - $GarbageOffsetStart) . ' bytes between ' . $GarbageOffsetStart . ' and ' . $GarbageOffsetEnd . '), but did find valid CBR stream starting at ' . $GarbageOffsetEnd;
                        } else {
                            $ThisFileInfo['warning'] .= "\n" . 'using data from VBR header even though could not find ' . MPEG_VALID_CHECK_FRAMES . ' consecutive MPEG-audio frames immediately after VBR header (garbage data for ' . ($GarbageOffsetEnd - $GarbageOffsetStart) . ' bytes between ' . $GarbageOffsetStart . ' and ' . $GarbageOffsetEnd . ')';
                        }
                    }
                }
                if (isset($ThisFileInfo['mpeg']['audio']['bitrate_mode']) && $ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr' && !isset($ThisFileInfo['mpeg']['audio']['VBR_method'])) {
                    // VBR file with no VBR header
                    $BitrateHistogram = true;
                }
                if ($BitrateHistogram) {
                    $ThisFileInfo['mpeg']['audio']['stereo_distribution'] = array('stereo' => 0, 'joint stereo' => 0, 'dual channel' => 0, 'mono' => 0);
                    $ThisFileInfo['mpeg']['audio']['version_distribution'] = array('1' => 0, '2' => 0, '2.5' => 0);
                    if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
                        if ($ThisFileInfo['mpeg']['audio']['layer'] == 'III') {
                            $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 40 => 0, 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 160 => 0, 192 => 0, 224 => 0, 256 => 0, 320 => 0);
                        } elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
                            $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 160 => 0, 192 => 0, 224 => 0, 256 => 0, 320 => 0, 384 => 0);
                        } elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                            $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 64 => 0, 96 => 0, 128 => 0, 160 => 0, 192 => 0, 224 => 0, 256 => 0, 288 => 0, 320 => 0, 352 => 0, 384 => 0, 416 => 0, 448 => 0);
                        }
                    } elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
                        $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 144 => 0, 160 => 0, 176 => 0, 192 => 0, 224 => 0, 256 => 0);
                    } else {
                        $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 8 => 0, 16 => 0, 24 => 0, 32 => 0, 40 => 0, 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 144 => 0, 160 => 0);
                    }
                    $dummy = array('error' => $ThisFileInfo['error'], 'warning' => $ThisFileInfo['warning'], 'avdataend' => $ThisFileInfo['avdataend'], 'avdataoffset' => $ThisFileInfo['avdataoffset']);
                    $synchstartoffset = $ThisFileInfo['avdataoffset'];
                    $FastMode = false;
                    while (decodeMPEGaudioHeader($fd, $synchstartoffset, $dummy, false, false, $FastMode)) {
                        $FastMode = true;
                        $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
                        $ThisFileInfo['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]++;
                        $ThisFileInfo['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]++;
                        $ThisFileInfo['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]++;
                        if (empty($dummy['mpeg']['audio']['framelength'])) {
                            $ThisFileInfo['warning'] .= "\n" . 'Invalid/missing framelength in histogram analysis - aborting';
                            $synchstartoffset += 4;
                            //							return false;
                        }
                        $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
                    }
                    $bittotal = 0;
                    $framecounter = 0;
                    foreach ($ThisFileInfo['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) {
                        $framecounter += $bitratecount;
                        if ($bitratevalue != 'free') {
                            $bittotal += $bitratevalue * $bitratecount;
                        }
                    }
                    if ($framecounter == 0) {
                        $ThisFileInfo['error'] .= "\n" . 'Corrupt MP3 file: framecounter == zero';
                        return false;
                    }
                    $ThisFileInfo['mpeg']['audio']['frame_count'] = $framecounter;
                    $ThisFileInfo['mpeg']['audio']['bitrate'] = 1000 * ($bittotal / $framecounter);
                    $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'];
                    // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
                    $distinct_bitrates = 0;
                    foreach ($ThisFileInfo['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
                        if ($bitrate_count > 0) {
                            $distinct_bitrates++;
                        }
                    }
                    if ($distinct_bitrates > 1) {
                        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
                    } else {
                        $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
                    }
                    $ThisFileInfo['audio']['bitrate_mode'] = $ThisFileInfo['mpeg']['audio']['bitrate_mode'];
                }
                break;
                // exit while()
            }
        }
        $SynchSeekOffset++;
        if ($avdataoffset + $SynchSeekOffset >= $ThisFileInfo['avdataend']) {
            // end of file/data
            if (empty($ThisFileInfo['mpeg']['audio'])) {
                $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
                if (isset($ThisFileInfo['audio']['bitrate'])) {
                    unset($ThisFileInfo['audio']['bitrate']);
                }
                if (isset($ThisFileInfo['mpeg']['audio'])) {
                    unset($ThisFileInfo['mpeg']['audio']);
                }
                if (isset($ThisFileInfo['mpeg']) && (!is_array($ThisFileInfo['mpeg']) || empty($ThisFileInfo['mpeg']))) {
                    unset($ThisFileInfo['mpeg']);
                }
                return false;
            }
            break;
        }
    }
    $ThisFileInfo['audio']['bits_per_sample'] = 16;
    $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
    $ThisFileInfo['audio']['channelmode'] = $ThisFileInfo['mpeg']['audio']['channelmode'];
    $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
    return true;
}
Ejemplo n.º 3
0
function getMPEGHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $ThisFileInfo['fileformat'] = 'mpeg';
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $MPEGstreamData = fread($fd, min(100000, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']));
    $MPEGstreamDataLength = strlen($MPEGstreamData);
    $foundVideo = true;
    $VideoChunkOffset = 0;
    while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== MPEG_VIDEO_SEQUENCE_HEADER) {
        if ($VideoChunkOffset >= $MPEGstreamDataLength) {
            $foundVideo = false;
            break 2;
        }
    }
    if ($foundVideo) {
        // Start code                       32 bits
        // horizontal frame size            12 bits
        // vertical frame size              12 bits
        // pixel aspect ratio                4 bits
        // frame rate                        4 bits
        // bitrate                          18 bits
        // marker bit                        1 bit
        // VBV buffer size                  10 bits
        // constrained parameter flag        1 bit
        // intra quant. matrix flag          1 bit
        // intra quant. matrix values      512 bits (present if matrix flag == 1)
        // non-intra quant. matrix flag      1 bit
        // non-intra quant. matrix values  512 bits (present if matrix flag == 1)
        $ThisFileInfo['video']['dataformat'] = 'mpeg';
        // I don't know how to differentiate between MPEG-1 and MPEG-2 video stream
        // Any information appreciated: info@getid3.org
        //$ThisFileInfo['video']['codec']      = 'MPEG-1';
        //$ThisFileInfo['video']['codec']      = 'MPEG-2';
        $ThisFileInfo['video']['codec'] = 'MPEG';
        $VideoChunkOffset += strlen(MPEG_VIDEO_SEQUENCE_HEADER) - 1;
        $FrameSizeDWORD = BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3));
        $VideoChunkOffset += 3;
        $AspectRatioFrameRateDWORD = BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1));
        $VideoChunkOffset += 1;
        $assortedinformation = BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4));
        $VideoChunkOffset += 4;
        $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xfff000) >> 12;
        // 12 bits for horizontal frame size
        $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'] = $FrameSizeDWORD & 0xfff;
        // 12 bits for vertical frame size
        $ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xf0) >> 4;
        $ThisFileInfo['mpeg']['video']['raw']['frame_rate'] = $AspectRatioFrameRateDWORD & 0xf;
        $ThisFileInfo['mpeg']['video']['framesize_horizontal'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'];
        $ThisFileInfo['mpeg']['video']['framesize_vertical'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'];
        $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'] = MPEGvideoAspectRatioLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio_text'] = MPEGvideoAspectRatioTextLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
        $ThisFileInfo['mpeg']['video']['frame_rate'] = MPEGvideoFramerateLookup($ThisFileInfo['mpeg']['video']['raw']['frame_rate']);
        $ThisFileInfo['mpeg']['video']['raw']['bitrate'] = Bin2Dec(substr($assortedinformation, 0, 18));
        $ThisFileInfo['mpeg']['video']['raw']['marker_bit'] = Bin2Dec(substr($assortedinformation, 18, 1));
        $ThisFileInfo['mpeg']['video']['raw']['vbv_buffer_size'] = Bin2Dec(substr($assortedinformation, 19, 10));
        $ThisFileInfo['mpeg']['video']['raw']['constrained_param_flag'] = Bin2Dec(substr($assortedinformation, 29, 1));
        $ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag'] = Bin2Dec(substr($assortedinformation, 30, 1));
        if ($ThisFileInfo['mpeg']['video']['raw']['bitrate'] == 0x3ffff) {
            // 18 set bits
            $ThisFileInfo['warning'] .= "\n" . 'This version of getID3() [' . GETID3VERSION . '] cannot determine average bitrate of VBR MPEG video files';
            $ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'vbr';
        } else {
            $ThisFileInfo['mpeg']['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['raw']['bitrate'] * 400;
            $ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['bitrate'];
        }
        $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['mpeg']['video']['framesize_horizontal'];
        $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['mpeg']['video']['framesize_vertical'];
        $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['mpeg']['video']['frame_rate'];
        $ThisFileInfo['video']['bitrate_mode'] = $ThisFileInfo['mpeg']['video']['bitrate_mode'];
        $ThisFileInfo['video']['lossless'] = false;
        $ThisFileInfo['video']['bits_per_sample'] = 24;
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?';
    }
    $AudioChunkOffset = 0;
    while (true) {
        while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== MPEG_AUDIO_START) {
            if ($AudioChunkOffset >= $MPEGstreamDataLength) {
                break 2;
            }
        }
        require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
        for ($i = 0; $i <= 2; $i++) {
            // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it 9 bytes, some 10 bytes after
            // I have no idea why or what the difference is, so this is a stupid hack.
            // If anybody has any better idea of what's going on, please let me know - info@getid3.org
            $dummy = $ThisFileInfo;
            if (decodeMPEGaudioHeader($fd, $AudioChunkOffset + 3 + 8 + $i, $dummy, false)) {
                $ThisFileInfo = $dummy;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                $ThisFileInfo['audio']['lossless'] = false;
                break 2;
            }
        }
    }
    return true;
}