Example #1
0
function getMP3headerFilepointer(&$fd, &$ThisFileInfo)
{
    getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset']);
    if (isset($ThisFileInfo['mpeg']['audio']['bitratemode'])) {
        $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']);
    }
    if (isset($ThisFileInfo['id3v2']) && $ThisFileInfo['avdataoffset'] > $ThisFileInfo['id3v2']['headerlength'] || !isset($ThisFileInfo['id3v2']) && $ThisFileInfo['avdataoffset'] > 0) {
        $ThisFileInfo['warning'] .= "\n" . 'Unknown data before synch ';
        if (isset($ThisFileInfo['id3v2']['headerlength'])) {
            $ThisFileInfo['warning'] .= '(ID3v2 header ends at ' . $ThisFileInfo['id3v2']['headerlength'] . ', ';
        } else {
            $ThisFileInfo['warning'] .= '(should be at beginning of file, ';
        }
        $ThisFileInfo['warning'] .= 'synch detected at ' . $ThisFileInfo['avdataoffset'] . ')';
        if ($ThisFileInfo['audio']['bitrate_mode'] == 'cbr' && $ThisFileInfo['avdataoffset'] == $ThisFileInfo['mpeg']['audio']['framelength']) {
            $ThisFileInfo['warning'] .= ' This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
            $ThisFileInfo['audio']['codec'] = 'LAME';
        }
    }
    if (isset($ThisFileInfo['mpeg']['audio']['layer']) && $ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
        $ThisFileInfo['fileformat'] = 'mp2';
        $ThisFileInfo['audio']['dataformat'] = 'mp2';
    } elseif (isset($ThisFileInfo['mpeg']['audio']['layer']) && $ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
        $ThisFileInfo['fileformat'] = 'mp1';
        $ThisFileInfo['audio']['dataformat'] = 'mp1';
    }
    if (empty($ThisFileInfo['fileformat'])) {
        $ThisFileInfo['error'] .= "\n" . 'Synch not found';
        unset($ThisFileInfo['fileformat']);
        unset($ThisFileInfo['audio']['bitrate_mode']);
        unset($ThisFileInfo['avdataoffset']);
        unset($ThisFileInfo['avdataend']);
        return false;
    }
    $ThisFileInfo['mime_type'] = 'audio/mpeg';
    // Calculate playtime from audiobytes etc
    if (!isset($ThisFileInfo['playtime_seconds']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0) {
        $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate'];
    }
    if (isset($ThisFileInfo['mpeg']['audio']['LAME'])) {
        $ThisFileInfo['audio']['codec'] = 'LAME';
        if (!empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
            $ThisFileInfo['audio']['encoder'] = trim($ThisFileInfo['mpeg']['audio']['LAME']['short_version']);
        }
    }
    return true;
}
function getMP3headerFilepointer(&$fd, &$ThisFileInfo)
{
    getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset']);
    if (isset($ThisFileInfo['mpeg']['audio']['bitrate_mode'])) {
        $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
    }
    if (isset($ThisFileInfo['id3v2']) && $ThisFileInfo['avdataoffset'] > $ThisFileInfo['id3v2']['headerlength'] || !isset($ThisFileInfo['id3v2']) && $ThisFileInfo['avdataoffset'] > 0) {
        $ThisFileInfo['warning'] .= "\n" . 'Unknown data before synch ';
        if (isset($ThisFileInfo['id3v2']['headerlength'])) {
            $ThisFileInfo['warning'] .= '(ID3v2 header ends at ' . $ThisFileInfo['id3v2']['headerlength'] . ', then ' . ($ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength']) . ' bytes garbage, ';
        } else {
            $ThisFileInfo['warning'] .= '(should be at beginning of file, ';
        }
        $ThisFileInfo['warning'] .= 'synch detected at ' . $ThisFileInfo['avdataoffset'] . ')';
        if ($ThisFileInfo['audio']['bitrate_mode'] == 'cbr') {
            if (!empty($ThisFileInfo['id3v2']['headerlength']) && $ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength'] == $ThisFileInfo['mpeg']['audio']['framelength']) {
                $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
                $ThisFileInfo['audio']['codec'] = 'LAME';
            } elseif (empty($ThisFileInfo['id3v2']['headerlength']) && $ThisFileInfo['avdataoffset'] == $ThisFileInfo['mpeg']['audio']['framelength']) {
                $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
                $ThisFileInfo['audio']['codec'] = 'LAME';
            }
        }
    }
    if (isset($ThisFileInfo['mpeg']['audio']['layer']) && $ThisFileInfo['mpeg']['audio']['layer'] == 'II') {
        $ThisFileInfo['audio']['dataformat'] = 'mp2';
    } elseif (isset($ThisFileInfo['mpeg']['audio']['layer']) && $ThisFileInfo['mpeg']['audio']['layer'] == 'I') {
        $ThisFileInfo['audio']['dataformat'] = 'mp1';
    }
    if ($ThisFileInfo['fileformat'] == 'mp3') {
        switch ($ThisFileInfo['audio']['dataformat']) {
            case 'mp1':
            case 'mp2':
            case 'mp3':
                $ThisFileInfo['fileformat'] = $ThisFileInfo['audio']['dataformat'];
                break;
            default:
                $ThisFileInfo['warning'] .= "\n" . 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "' . $ThisFileInfo['audio']['dataformat'] . '"';
                break;
        }
    }
    if (empty($ThisFileInfo['fileformat'])) {
        $ThisFileInfo['error'] .= "\n" . 'Synch not found';
        unset($ThisFileInfo['fileformat']);
        unset($ThisFileInfo['audio']['bitrate_mode']);
        unset($ThisFileInfo['avdataoffset']);
        unset($ThisFileInfo['avdataend']);
        return false;
    }
    $ThisFileInfo['mime_type'] = 'audio/mpeg';
    $ThisFileInfo['audio']['lossless'] = false;
    // Calculate playtime
    if (!isset($ThisFileInfo['playtime_seconds']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0) {
        $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate'];
    }
    if (isset($ThisFileInfo['mpeg']['audio']['LAME'])) {
        $ThisFileInfo['audio']['codec'] = 'LAME';
        if (!empty($ThisFileInfo['mpeg']['audio']['LAME']['long_version'])) {
            $ThisFileInfo['audio']['encoder'] = trim($ThisFileInfo['mpeg']['audio']['LAME']['long_version']);
        }
    }
    return true;
}
function getQuicktimeHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $ThisFileInfo['fileformat'] = 'quicktime';
    $ThisFileInfo['audio']['dataformat'] = 'quicktime';
    $ThisFileInfo['video']['dataformat'] = 'quicktime';
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $offset = 0;
    $atomcounter = 0;
    while ($offset < $ThisFileInfo['avdataend']) {
        fseek($fd, $offset, SEEK_SET);
        $AtomHeader = fread($fd, 8);
        $atomsize = BigEndian2Int(substr($AtomHeader, 0, 4));
        $atomname = substr($AtomHeader, 4, 4);
        $ThisFileInfo['quicktime']["{$atomname}"]['name'] = $atomname;
        $ThisFileInfo['quicktime']["{$atomname}"]['size'] = $atomsize;
        $ThisFileInfo['quicktime']["{$atomname}"]['offset'] = $offset;
        if ($offset + $atomsize > $ThisFileInfo['avdataend']) {
            $ThisFileInfo['error'] .= "\n" . 'Atom at offset ' . $offset . ' claims to go beyond end-of-file (length: ' . $atomsize . ' bytes)';
            return false;
        }
        switch ($atomname) {
            case 'mdat':
                // Media DATa atom
                // 'mdat' contains the actual data for the audio/video
                if (!isset($ThisFileInfo['avdataend_tmp']) || $ThisFileInfo['quicktime']["{$atomname}"]['size'] > $ThisFileInfo['avdataend_tmp'] - $ThisFileInfo['avdataoffset']) {
                    $ThisFileInfo['avdataoffset'] = $ThisFileInfo['quicktime']["{$atomname}"]['offset'] + 8;
                    $OldAVDataEnd = $ThisFileInfo['avdataend'];
                    $ThisFileInfo['avdataend'] = $ThisFileInfo['quicktime']["{$atomname}"]['offset'] + $ThisFileInfo['quicktime']["{$atomname}"]['size'];
                    require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                    if (MPEGaudioHeaderValid(MPEGaudioHeaderDecode(fread($fd, 4)))) {
                        getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset'], false);
                        if (isset($ThisFileInfo['mpeg']['audio'])) {
                            $ThisFileInfo['audio']['dataformat'] = 'mp3';
                            $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
                            $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
                            $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000;
                            $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']);
                            $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
                        }
                    }
                    $ThisFileInfo['avdataend'] = $OldAVDataEnd;
                    unset($OldAVDataEnd);
                }
                break;
            case 'free':
                // FREE space atom
            // FREE space atom
            case 'skip':
                // SKIP atom
            // SKIP atom
            case 'wide':
                // 64-bit expansion placeholder atom
                // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
                break;
            default:
                $atomHierarchy = array();
                $ThisFileInfo['quicktime']["{$atomname}"] = QuicktimeParseAtom($atomname, $atomsize, fread($fd, $atomsize), $ThisFileInfo, $offset, $atomHierarchy);
                break;
        }
        $offset += $atomsize;
        $atomcounter++;
    }
    if (!empty($ThisFileInfo['avdataend_tmp'])) {
        // this value is assigned to a temp value and then erased because
        // otherwise any atoms beyond the 'mdat' atom would not get parsed
        $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataend_tmp'];
        unset($ThisFileInfo['avdataend_tmp']);
    }
    // Quicktime tags have highest priority
    if (isset($ThisFileInfo['quicktime']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['quicktime']['comments'], $ThisFileInfo, true, true, true);
        // add tag to array of tags
        $ThisFileInfo['tags'][] = 'quicktime';
    }
    if (!isset($ThisFileInfo['bitrate']) && isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
    }
    if (isset($ThisFileInfo['bitrate']) && !isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['quicktime']['video'])) {
        $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['bitrate'];
    }
    return true;
}
function getMP3headerFilepointer(&$fd, &$MP3fileInfo)
{
    // get all information about an MP3 file - ID3v1, ID3v2, Lyrics3, MPEG-audio
    $MP3fileInfo['fileformat'] = '';
    if (!$fd) {
        $MP3fileInfo['error'] .= "\n" . 'Could not open file';
        return FALSE;
    } else {
        fseek($fd, -128 - 9 - 6, SEEK_END);
        $lyrics3_id3v1 = fread($fd, 128 + 9 + 6);
        $lyrics3lsz = substr($lyrics3_id3v1, 0, 6);
        $lyrics3end = substr($lyrics3_id3v1, 6, 9);
        // LYRICSEND or LYRICS200
        $id3v1tag = substr($lyrics3_id3v1, 15, 128);
        if ($lyrics3end == 'LYRICSEND') {
            // Lyrics3 v1 and ID3v1
            $lyrics3size = 5100;
            include_once GETID3_INCLUDEPATH . 'getid3.lyrics3.php';
            getLyrics3Filepointer($MP3fileInfo, $fd, -128 - $lyrics3size, 1, $lyrics3size);
        } else {
            if ($lyrics3end == 'LYRICS200') {
                // Lyrics3 v2 and ID3v1
                $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
                // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
                include_once GETID3_INCLUDEPATH . 'getid3.lyrics3.php';
                getLyrics3Filepointer($MP3fileInfo, $fd, -128 - $lyrics3size, 2, $lyrics3size);
            } else {
                if (substr($lyrics3_id3v1, strlen($lyrics3_id3v1) - 1 - 9, 9) == 'LYRICSEND') {
                    // Lyrics3 v1, no ID3v1 (I think according to Lyrics3 specs there MUST be ID3v1, but just in case :)
                    $lyrics3size = 5100;
                    include_once GETID3_INCLUDEPATH . 'getid3.lyrics3.php';
                    getLyrics3Filepointer($MP3fileInfo, $fd, 0 - $lyrics3size, 1, $lyrics3size);
                } else {
                    if (substr($lyrics3_id3v1, strlen($lyrics3_id3v1) - 1 - 9, 9) == 'LYRICS200') {
                        // Lyrics3 v2, no ID3v1 (I think according to Lyrics3 specs there MUST be ID3v1, but just in case :)
                        $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
                        // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
                        include_once GETID3_INCLUDEPATH . 'getid3.lyrics3.php';
                        getLyrics3Filepointer($MP3fileInfo, $fd, 0 - $lyrics3size, 2, $lyrics3size);
                    }
                }
            }
        }
        if (substr($id3v1tag, 0, 3) == 'TAG') {
            include_once GETID3_INCLUDEPATH . 'getid3.id3v1.php';
            $MP3fileInfo['id3']['id3v1'] = getID3v1Filepointer($fd);
            $MP3fileInfo['fileformat'] = 'id3';
        }
        include_once GETID3_INCLUDEPATH . 'getid3.id3v2.php';
        getID3v2Filepointer($fd, $MP3fileInfo);
        if (isset($MP3fileInfo['id3']['id3v2']['header'])) {
            $MP3fileInfo['fileformat'] = 'id3';
            $audiodataoffset = $MP3fileInfo['id3']['id3v2']['headerlength'];
            if (isset($MP3fileInfo['id3']['id3v2']['footer'])) {
                $audiodataoffset += 10;
            }
        } else {
            // no ID3v2 header
            if (isset($MP3fileInfo['id3']['id3v2'])) {
                unset($MP3fileInfo['id3']['id3v2']);
            }
            $audiodataoffset = 0;
        }
        if ($audiodataoffset < $MP3fileInfo['filesize']) {
            getOnlyMPEGaudioInfo($fd, $MP3fileInfo, $audiodataoffset);
        }
        if (isset($MP3fileInfo['audiodataoffset']) && (isset($MP3fileInfo['id3']['id3v2']) && $MP3fileInfo['audiodataoffset'] > $MP3fileInfo['id3']['id3v2']['headerlength'] || !isset($MP3fileInfo['id3']['id3v2']) && $MP3fileInfo['audiodataoffset'] > 0)) {
            $MP3fileInfo['error'] .= "\n" . 'Unknown data before synch ';
            if (isset($MP3fileInfo['id3']['id3v2']['headerlength'])) {
                $MP3fileInfo['error'] .= '(ID3v2 header ends at ' . $MP3fileInfo['id3']['id3v2']['headerlength'] . ', ';
            } else {
                $MP3fileInfo['error'] .= '(should be at beginning of file, ';
            }
            $MP3fileInfo['error'] .= 'synch detected at ' . $MP3fileInfo['audiodataoffset'] . ')';
        }
        if (!$MP3fileInfo['fileformat']) {
            $MP3fileInfo['error'] .= "\n" . 'Synch not found';
            unset($MP3fileInfo['audiodataoffset']);
            unset($MP3fileInfo['fileformat']);
        }
    }
    // if ($fd)
    if (isset($MP3fileInfo['id3']) && !isset($MP3fileInfo['id3']['id3v2']) && !isset($MP3fileInfo['id3']['id3v1'])) {
        unset($MP3fileInfo['id3']);
    }
    return TRUE;
}
Example #5
0
function ParseRIFF(&$fd, $startoffset, $maxoffset, &$ThisFileInfo)
{
    $maxoffset = min($maxoffset, $ThisFileInfo['avdataend']);
    $RIFFchunk = false;
    fseek($fd, $startoffset, SEEK_SET);
    while (ftell($fd) < $maxoffset) {
        $chunkname = fread($fd, 4);
        $chunksize = EitherEndian2Int($ThisFileInfo, fread($fd, 4));
        if ($chunksize % 2 != 0) {
            // all structures are packed on word boundaries
            $chunksize++;
        }
        switch ($chunkname) {
            case 'LIST':
                $listname = fread($fd, 4);
                switch ($listname) {
                    case 'movi':
                    case 'rec ':
                        // skip over
                        $RIFFchunk["{$listname}"]['offset'] = ftell($fd) - 4;
                        $RIFFchunk["{$listname}"]['size'] = $chunksize;
                        fseek($fd, $chunksize - 4, SEEK_CUR);
                        break;
                    default:
                        if (!isset($RIFFchunk["{$listname}"])) {
                            $RIFFchunk["{$listname}"] = array();
                        }
                        $RIFFchunk["{$listname}"] = array_merge_recursive($RIFFchunk["{$listname}"], ParseRIFF($fd, ftell($fd), ftell($fd) + $chunksize - 4, $ThisFileInfo));
                        break;
                }
                break;
            default:
                $thisindex = 0;
                if (isset($RIFFchunk["{$chunkname}"]) && is_array($RIFFchunk["{$chunkname}"])) {
                    $thisindex = count($RIFFchunk["{$chunkname}"]);
                }
                $RIFFchunk["{$chunkname}"][$thisindex]['offset'] = ftell($fd) - 8;
                $RIFFchunk["{$chunkname}"][$thisindex]['size'] = $chunksize;
                switch ($chunkname) {
                    case 'data':
                        $RIFFdataChunkContentsTest = fread($fd, 8);
                        if (strlen($RIFFdataChunkContentsTest) > 0 && $RIFFdataChunkContentsTest[0] == chr(0xff)) {
                            // Probably (but not guaranteed) that this is MP3 data
                            require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                            if (MPEGaudioHeaderBytesValid(substr($RIFFdataChunkContentsTest, 0, 4))) {
                                $WhereWeWere = ftell($fd);
                                getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $RIFFchunk["{$chunkname}"][$thisindex]['offset'], false);
                                fseek($fd, $WhereWeWere, SEEK_SET);
                                if (isset($ThisFileInfo['mpeg']['audio'])) {
                                    $ThisFileInfo['audio']['dataformat'] = 'mp' . strlen($ThisFileInfo['mpeg']['audio']['layer']);
                                    $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
                                    $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
                                    $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000;
                                    $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
                                    $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
                                }
                                fseek($fd, $chunksize - 8, SEEK_CUR);
                            }
                        } else {
                            if (substr($RIFFdataChunkContentsTest, 0, 4) == 'wvpk') {
                                // This is WavPack data
                                $ThisFileInfo['wavpack']['offset'] = ftell($fd) - 8;
                                $ThisFileInfo['wavpack']['size'] = LittleEndian2Int(substr($RIFFdataChunkContentsTest, 4, 4));
                                $WavPackData = fread($fd, $ThisFileInfo['wavpack']['size']);
                                RIFFparseWavPackHeader($WavPackData, $ThisFileInfo);
                                fseek($fd, $chunksize - 8 - $ThisFileInfo['wavpack']['size'], SEEK_CUR);
                            } else {
                                // This is some other kind of data (quite possibly just PCM)
                                // do nothing special, just skip it
                                fseek($fd, $chunksize - 8, SEEK_CUR);
                            }
                        }
                        break;
                    case 'bext':
                    case 'cart':
                    case 'fmt ':
                    case 'MEXT':
                    case 'DISP':
                        // always read data in
                        $RIFFchunk["{$chunkname}"][$thisindex]['data'] = fread($fd, $chunksize);
                        break;
                    default:
                        // read data in if smaller than 2kB
                        if ($chunksize < 2048) {
                            $RIFFchunk["{$chunkname}"][$thisindex]['data'] = fread($fd, $chunksize);
                        } else {
                            fseek($fd, $chunksize, SEEK_CUR);
                        }
                        break;
                }
                break;
        }
    }
    return $RIFFchunk;
}
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
            $ThisFileInfo['fileformat'] = 'riff';
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + LittleEndian2Int(substr($RIFFheader, 4, 4)), $ThisFileInfo);
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
            unset($ThisFileInfo['fileformat']);
            return false;
            break;
    }
    $streamindex = 0;
    $arraykeys = array_keys($ThisFileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'wav';
            if (isset($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data']);
                if ($ThisFileInfo['RIFF']['audio'][$streamindex] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: bitrate_audio == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['fmt '] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
                if (isset($ThisFileInfo['RIFF']['WAVE']['data'][0]['offset']) && isset($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag'])) {
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 85:
                            // LAME ACM
                            require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                            getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['RIFF']['WAVE']['data'][0]['offset'], false);
                            $ThisFileInfo['audio']['dataformat'] = 'mp3';
                            if (isset($ThisFileInfo['mpeg']['audio'])) {
                                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
                                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
                                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000;
                                $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
                                $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']);
                            }
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                $rgadData = $ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = LittleEndian2Int(substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = LittleEndian2Int(substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['rgad']['peakamplitude'] = $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] > 0) {
                    $ThisFileInfo['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $ThisFileInfo['audio']['bitrate'] = CastAsInt($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (!isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = LittleEndian2Int(substr($avihData, 0, 4));
                // frame display rate (or 0L)
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = LittleEndian2Int(substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = LittleEndian2Int(substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = LittleEndian2Int(substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = LittleEndian2Int(substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = LittleEndian2Int(substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = LittleEndian2Int(substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = LittleEndian2Int(substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = LittleEndian2Int(substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = LittleEndian2Int(substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = LittleEndian2Int(substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = LittleEndian2Int(substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = LittleEndian2Int(substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = LittleEndian2Int(substr($avihData, 52, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                if (!isset($ThisFileInfo['video']['resolution_x'])) {
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if (!isset($ThisFileInfo['video']['resolution_y'])) {
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                            $strhData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                            $strhfccType = substr($strhData, 0, 4);
                            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                $strfData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                switch ($strhfccType) {
                                    case 'auds':
                                        $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                                        $ThisFileInfo['audio']['dataformat'] = 'wav';
                                        if (isset($ThisFileInfo['RIFF']['audio']) && is_array($ThisFileInfo['RIFF']['audio'])) {
                                            $streamindex = count($ThisFileInfo['RIFF']['audio']);
                                        }
                                        $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($strfData);
                                        $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                                        unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                                        $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 85:
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                $ThisFileInfo['audio']['dataformat'] = 'ac3';
                                                break;
                                            default:
                                                $ThisFileInfo['audio']['dataformat'] = 'wav';
                                                break;
                                        }
                                        break;
                                    case 'iavs':
                                    case 'vids':
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccType'] = substr($strhData, 0, 4);
                                        // same as $strhfccType;
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler'] = substr($strhData, 4, 4);
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwFlags'] = LittleEndian2Int(substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = LittleEndian2Int(substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = LittleEndian2Int(substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = LittleEndian2Int(substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = LittleEndian2Int(substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = LittleEndian2Int(substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = LittleEndian2Int(substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = LittleEndian2Int(substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = LittleEndian2Int(substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = LittleEndian2Int(substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = LittleEndian2Int(substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = LittleEndian2Int(substr($strhData, 48, 4));
                                        $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']);
                                        if (!$ThisFileInfo['RIFF']['video'][$streamindex]['codec'] && isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                                        }
                                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = LittleEndian2Int(substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = LittleEndian2Int(substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = LittleEndian2Int(substr($strfData, 8, 4));
                                                // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biPlanes'] = LittleEndian2Int(substr($strfData, 12, 2));
                                                // number of color planes on the target device. In most cases this value must be set to 1
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'] = LittleEndian2Int(substr($strfData, 14, 2));
                                                // Specifies the number of bits per pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'] = substr($strfData, 16, 4);
                                                //
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSizeImage'] = LittleEndian2Int(substr($strfData, 20, 4));
                                                // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biXPelsPerMeter'] = LittleEndian2Int(substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = LittleEndian2Int(substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = LittleEndian2Int(substr($strfData, 32, 4));
                                                // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrImportant'] = LittleEndian2Int(substr($strfData, 36, 4));
                                                // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                if ($ThisFileInfo['RIFF']['video'][$streamindex]['codec'] == 'DV') {
                                                    $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 2;
                                                }
                                                break;
                                            case 'iavs':
                                                $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 1;
                                                break;
                                        }
                                        break;
                                    default:
                                        $ThisFileInfo['warning'] .= "\n" . 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                        break;
                                }
                            }
                        }
                        if (isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                            $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            unset($ThisFileInfo['mime_type']);
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = LittleEndian2Int(substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = LittleEndian2Int(substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = LittleEndian2Int(substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = LittleEndian2Int(substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = LittleEndian2Int(substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = LittleEndian2Int(substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = LittleEndian2Int(substr($fmtData, 20, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] / 75;
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] / 75;
                $ThisFileInfo['comments']['track'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'];
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'];
                // hardcoded data for CD-audio
                $ThisFileInfo['audio']['sample_rate'] = 44100;
                $ThisFileInfo['audio']['channels'] = 2;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['bits_per_sample'];
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            break;
        default:
            unset($ThisFileInfo['fileformat']);
            break;
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['DISP']) && is_array($ThisFileInfo['RIFF']['WAVE']['DISP'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $ThisFileInfo['RIFF']['comments']['title'][] = trim(substr($ThisFileInfo['RIFF']['WAVE']['DISP'][count($ThisFileInfo['RIFF']['WAVE']['DISP']) - 1]['data'], 4));
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']) && is_array($ThisFileInfo['RIFF']['WAVE']['INFO'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $RIFFinfoKeyLookup = array('IART' => 'artist', 'IGNR' => 'genre', 'ICMT' => 'comment', 'ICOP' => 'copyright', 'IENG' => 'engineers', 'IKEY' => 'keywords', 'IMED' => 'orignalmedium', 'INAM' => 'name', 'ISRC' => 'sourcesupplier', 'ITCH' => 'digitizer', 'ISBJ' => 'subject', 'ISRF' => 'digitizationsource');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            foreach ($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"] as $commentid => $commentdata) {
                if (trim($commentdata['data']) != '') {
                    $ThisFileInfo['RIFF']['comments']["{$value}"][] = trim($commentdata['data']);
                }
            }
        }
    }
    if (!empty($ThisFileInfo['RIFF']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
    }
    if (!isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['playtime_seconds'] = 0;
    }
    if (isset($ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames']) && isset($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'])) {
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
    }
    if ($ThisFileInfo['playtime_seconds'] > 0) {
        if (isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['bitrate'])) {
                $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (isset($ThisFileInfo['RIFF']['audio']) && !isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (!isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['video']['bitrate'])) {
                $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        }
    }
    if (isset($ThisFileInfo['RIFF']['video']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
        $ThisFileInfo['audio']['bitrate'] = 0;
        $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
        foreach ($ThisFileInfo['RIFF']['audio'] as $channelnumber => $audioinfoarray) {
            $ThisFileInfo['video']['bitrate'] -= $audioinfoarray['bitrate'];
            $ThisFileInfo['audio']['bitrate'] += $audioinfoarray['bitrate'];
        }
        if ($ThisFileInfo['video']['bitrate'] <= 0) {
            unset($ThisFileInfo['video']['bitrate']);
        }
        if ($ThisFileInfo['audio']['bitrate'] <= 0) {
            unset($ThisFileInfo['audio']['bitrate']);
        }
    }
    if (!empty($ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'])) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    // Skip RIFF header
    $ThisFileInfo['avdataoffset'] += 44;
    return true;
}