function QuicktimeParseAtom($atomname, $atomsize, $atomdata, &$ThisFileInfo, $baseoffset, &$atomHierarchy)
{
    // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
    array_push($atomHierarchy, $atomname);
    $atomstructure['hierarchy'] = implode(' ', $atomHierarchy);
    $atomstructure['name'] = $atomname;
    $atomstructure['size'] = $atomsize;
    $atomstructure['offset'] = $baseoffset;
    switch ($atomname) {
        case 'moov':
            // MOVie container atom
        // MOVie container atom
        case 'trak':
            // TRAcK container atom
        // TRAcK container atom
        case 'clip':
            // CLIPping container atom
        // CLIPping container atom
        case 'matt':
            // track MATTe container atom
        // track MATTe container atom
        case 'edts':
            // EDiTS container atom
        // EDiTS container atom
        case 'tref':
            // Track REFerence container atom
        // Track REFerence container atom
        case 'mdia':
            // MeDIA container atom
        // MeDIA container atom
        case 'minf':
            // Media INFormation container atom
        // Media INFormation container atom
        case 'dinf':
            // Data INFormation container atom
        // Data INFormation container atom
        case 'udta':
            // User DaTA container atom
        // User DaTA container atom
        case 'stbl':
            // Sample TaBLe container atom
        // Sample TaBLe container atom
        case 'cmov':
            // Compressed MOVie container atom
        // Compressed MOVie container atom
        case 'rmra':
            // Reference Movie Record Atom
        // Reference Movie Record Atom
        case 'rmda':
            // Reference Movie Descriptor Atom
            $atomstructure['subatoms'] = QuicktimeParseContainerAtom($atomdata, $ThisFileInfo, $baseoffset + 8, $atomHierarchy);
            break;
        case '©cpy':
        case '©day':
        case '©dir':
        case '©ed1':
        case '©ed2':
        case '©ed3':
        case '©ed4':
        case '©ed5':
        case '©ed6':
        case '©ed7':
        case '©ed8':
        case '©ed9':
        case '©fmt':
        case '©inf':
        case '©prd':
        case '©prf':
        case '©req':
        case '©src':
        case '©wrt':
        case '©nam':
        case '©cmt':
        case '©wrn':
        case '©hst':
        case '©mak':
        case '©mod':
        case '©PRD':
        case '©swr':
        case '©aut':
        case '©ART':
        case '©trk':
        case '©alb':
        case '©com':
        case '©gen':
        case '©ope':
        case '©url':
        case '©enc':
            $atomstructure['data_length'] = BigEndian2Int(substr($atomdata, 0, 2));
            $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 2, 2));
            $atomstructure['data'] = substr($atomdata, 4);
            $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']);
            $handyatomtranslatorarray['©cpy'] = 'copyright';
            $handyatomtranslatorarray['©day'] = 'creation_date';
            $handyatomtranslatorarray['©dir'] = 'director';
            $handyatomtranslatorarray['©ed1'] = 'edit1';
            $handyatomtranslatorarray['©ed2'] = 'edit2';
            $handyatomtranslatorarray['©ed3'] = 'edit3';
            $handyatomtranslatorarray['©ed4'] = 'edit4';
            $handyatomtranslatorarray['©ed5'] = 'edit5';
            $handyatomtranslatorarray['©ed6'] = 'edit6';
            $handyatomtranslatorarray['©ed7'] = 'edit7';
            $handyatomtranslatorarray['©ed8'] = 'edit8';
            $handyatomtranslatorarray['©ed9'] = 'edit9';
            $handyatomtranslatorarray['©fmt'] = 'format';
            $handyatomtranslatorarray['©inf'] = 'information';
            $handyatomtranslatorarray['©prd'] = 'producer';
            $handyatomtranslatorarray['©prf'] = 'performers';
            $handyatomtranslatorarray['©req'] = 'system_requirements';
            $handyatomtranslatorarray['©src'] = 'source_credit';
            $handyatomtranslatorarray['©wrt'] = 'writer';
            // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
            $handyatomtranslatorarray['©nam'] = 'title';
            $handyatomtranslatorarray['©cmt'] = 'comment';
            $handyatomtranslatorarray['©wrn'] = 'warning';
            $handyatomtranslatorarray['©hst'] = 'host_computer';
            $handyatomtranslatorarray['©mak'] = 'make';
            $handyatomtranslatorarray['©mod'] = 'model';
            $handyatomtranslatorarray['©PRD'] = 'product';
            $handyatomtranslatorarray['©swr'] = 'software';
            $handyatomtranslatorarray['©aut'] = 'author';
            $handyatomtranslatorarray['©ART'] = 'artist';
            $handyatomtranslatorarray['©trk'] = 'track';
            $handyatomtranslatorarray['©alb'] = 'album';
            $handyatomtranslatorarray['©com'] = 'comment';
            $handyatomtranslatorarray['©gen'] = 'genre';
            $handyatomtranslatorarray['©ope'] = 'composer';
            $handyatomtranslatorarray['©url'] = 'url';
            $handyatomtranslatorarray['©enc'] = 'encoder';
            if (isset($handyatomtranslatorarray["{$atomname}"])) {
                $ThisFileInfo['quicktime']['comments'][$handyatomtranslatorarray["{$atomname}"]][] = $atomstructure['data'];
            }
            break;
        case 'play':
            // auto-PLAY atom
            $atomstructure['autoplay'] = (bool) BigEndian2Int(substr($atomdata, 0, 1));
            $ThisFileInfo['quicktime']['autoplay'] = $atomstructure['autoplay'];
            break;
        case 'WLOC':
            // Window LOCation atom
            $atomstructure['location_x'] = BigEndian2Int(substr($atomdata, 0, 2));
            $atomstructure['location_y'] = BigEndian2Int(substr($atomdata, 2, 2));
            break;
        case 'LOOP':
            // LOOPing atom
        // LOOPing atom
        case 'SelO':
            // play SELection Only atom
        // play SELection Only atom
        case 'AllF':
            // play ALL Frames atom
            $atomstructure['data'] = BigEndian2Int($atomdata);
            break;
        case 'name':
            //
        //
        case 'MCPS':
            // Media Cleaner PRo
        // Media Cleaner PRo
        case '@PRM':
            // adobe PReMiere version
        // adobe PReMiere version
        case '@PRQ':
            // adobe PRemiere Quicktime version
            $atomstructure['data'] = $atomdata;
            break;
        case 'cmvd':
            // Compressed MooV Data atom
            $ThisFileInfo['warning'] .= "\n" . 'Compressed Quicktime MOOV Data atoms ("cmvd") not supported';
            break;
        case 'dcom':
            // Data COMpression atom
            $atomstructure['compression_id'] = $atomdata;
            $atomstructure['compression_text'] = QuicktimeDCOMLookup($atomdata);
            break;
        case 'rdrf':
            // Reference movie Data ReFerence atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            $atomstructure['flags']['internal_data'] = (bool) ($atomstructure['flags_raw'] & 0x1);
            $atomstructure['reference_type_name'] = substr($atomdata, 4, 4);
            $atomstructure['reference_length'] = BigEndian2Int(substr($atomdata, 8, 4));
            switch ($atomstructure['reference_type_name']) {
                case 'url ':
                    $atomstructure['url'] = NoNullString(substr($atomdata, 12));
                    break;
                case 'alis':
                    $atomstructure['file_alias'] = substr($atomdata, 12);
                    break;
                case 'rsrc':
                    $atomstructure['resource_alias'] = substr($atomdata, 12);
                    break;
                default:
                    $atomstructure['data'] = substr($atomdata, 12);
                    break;
            }
            break;
        case 'rmqu':
            // Reference Movie QUality atom
            $atomstructure['movie_quality'] = BigEndian2Int($atomdata);
            break;
        case 'rmcs':
            // Reference Movie Cpu Speed atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['cpu_speed_rating'] = BigEndian2Int(substr($atomdata, 4, 2));
            break;
        case 'rmvc':
            // Reference Movie Version Check atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['gestalt_selector'] = substr($atomdata, 4, 4);
            $atomstructure['gestalt_value_mask'] = BigEndian2Int(substr($atomdata, 8, 4));
            $atomstructure['gestalt_value'] = BigEndian2Int(substr($atomdata, 12, 4));
            $atomstructure['gestalt_check_type'] = BigEndian2Int(substr($atomdata, 14, 2));
            break;
        case 'rmcd':
            // Reference Movie Component check atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['component_type'] = substr($atomdata, 4, 4);
            $atomstructure['component_subtype'] = substr($atomdata, 8, 4);
            $atomstructure['component_manufacturer'] = substr($atomdata, 12, 4);
            $atomstructure['component_flags_raw'] = BigEndian2Int(substr($atomdata, 16, 4));
            $atomstructure['component_flags_mask'] = BigEndian2Int(substr($atomdata, 20, 4));
            $atomstructure['component_min_version'] = BigEndian2Int(substr($atomdata, 24, 4));
            break;
        case 'rmdr':
            // Reference Movie Data Rate atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['data_rate'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['data_rate_bps'] = $atomstructure['data_rate'] * 10;
            break;
        case 'rmla':
            // Reference Movie Language Atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 4, 2));
            $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']);
            break;
        case 'rmla':
            // Reference Movie Language Atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['track_id'] = BigEndian2Int(substr($atomdata, 4, 2));
            break;
        case 'stsd':
            // Sample Table Sample Description atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $stsdEntriesDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['sample_description_table'][$i]['size'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 4));
                $stsdEntriesDataOffset += 4;
                $atomstructure['sample_description_table'][$i]['data_format'] = substr($atomdata, $stsdEntriesDataOffset, 4);
                $stsdEntriesDataOffset += 4;
                $atomstructure['sample_description_table'][$i]['reserved'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 6));
                $stsdEntriesDataOffset += 6;
                $atomstructure['sample_description_table'][$i]['reference_index'] = BigEndian2Int(substr($atomdata, $stsdEntriesDataOffset, 2));
                $stsdEntriesDataOffset += 2;
                $atomstructure['sample_description_table'][$i]['data'] = substr($atomdata, $stsdEntriesDataOffset, $atomstructure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
                $stsdEntriesDataOffset += $atomstructure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2;
                $atomstructure['sample_description_table'][$i]['encoder_version'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 0, 2));
                $atomstructure['sample_description_table'][$i]['encoder_revision'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 2, 2));
                $atomstructure['sample_description_table'][$i]['encoder_vendor'] = substr($atomstructure['sample_description_table'][$i]['data'], 4, 4);
                if ($atomstructure['sample_description_table'][$i]['encoder_vendor'] == chr(0) . chr(0) . chr(0) . chr(0)) {
                    // audio atom
                    $atomstructure['sample_description_table'][$i]['audio_channels'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 8, 2));
                    $atomstructure['sample_description_table'][$i]['audio_bit_depth'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 10, 2));
                    $atomstructure['sample_description_table'][$i]['audio_compression_id'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 12, 2));
                    $atomstructure['sample_description_table'][$i]['audio_packet_size'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 14, 2));
                    $atomstructure['sample_description_table'][$i]['audio_sample_rate'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 16, 4));
                    $ThisFileInfo['quicktime']['audio']['codec'] = QuicktimeAudioCodecLookup($atomstructure['sample_description_table'][$i]['data_format']);
                    $ThisFileInfo['quicktime']['audio']['sample_rate'] = $atomstructure['sample_description_table'][$i]['audio_sample_rate'];
                    $ThisFileInfo['quicktime']['audio']['channels'] = $atomstructure['sample_description_table'][$i]['audio_channels'];
                    $ThisFileInfo['quicktime']['audio']['bit_depth'] = $atomstructure['sample_description_table'][$i]['audio_bit_depth'];
                    $ThisFileInfo['audio']['codec'] = $ThisFileInfo['quicktime']['audio']['codec'];
                    $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['quicktime']['audio']['sample_rate'];
                    $ThisFileInfo['audio']['channels'] = $ThisFileInfo['quicktime']['audio']['channels'];
                    $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['quicktime']['audio']['bit_depth'];
                } else {
                    // video atom
                    $atomstructure['sample_description_table'][$i]['video_temporal_quality'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 8, 4));
                    $atomstructure['sample_description_table'][$i]['video_spatial_quality'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 12, 4));
                    $atomstructure['sample_description_table'][$i]['video_frame_width'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 16, 2));
                    $atomstructure['sample_description_table'][$i]['video_frame_height'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 18, 2));
                    $atomstructure['sample_description_table'][$i]['video_resolution_x'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 20, 4));
                    $atomstructure['sample_description_table'][$i]['video_resolution_y'] = FixedPoint16_16(substr($atomstructure['sample_description_table'][$i]['data'], 24, 4));
                    $atomstructure['sample_description_table'][$i]['video_data_size'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 28, 4));
                    $atomstructure['sample_description_table'][$i]['video_frame_count'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 32, 2));
                    $atomstructure['sample_description_table'][$i]['video_encoder_name_len'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 34, 1));
                    $atomstructure['sample_description_table'][$i]['video_encoder_name'] = substr($atomstructure['sample_description_table'][$i]['data'], 35, $atomstructure['sample_description_table'][$i]['video_encoder_name_len']);
                    $atomstructure['sample_description_table'][$i]['video_pixel_color_depth'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 66, 2));
                    $atomstructure['sample_description_table'][$i]['video_color_table_id'] = BigEndian2Int(substr($atomstructure['sample_description_table'][$i]['data'], 68, 2));
                    $atomstructure['sample_description_table'][$i]['video_pixel_color_type'] = $atomstructure['sample_description_table'][$i]['video_pixel_color_depth'] > 32 ? 'grayscale' : 'color';
                    $atomstructure['sample_description_table'][$i]['video_pixel_color_name'] = QuicktimeColorNameLookup($atomstructure['sample_description_table'][$i]['video_pixel_color_depth']);
                    if ($atomstructure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
                        //$ThisFileInfo['quicktime']['video']['codec']            = QuicktimeVideoCodecLookup($atomstructure['sample_description_table'][$i]['data_format']);
                        $ThisFileInfo['quicktime']['video']['codec'] = $atomstructure['sample_description_table'][$i]['video_encoder_name'];
                        $ThisFileInfo['quicktime']['video']['color_depth'] = $atomstructure['sample_description_table'][$i]['video_pixel_color_depth'];
                        $ThisFileInfo['quicktime']['video']['color_depth_name'] = $atomstructure['sample_description_table'][$i]['video_pixel_color_name'];
                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['quicktime']['video']['codec'];
                    }
                }
                switch ($atomstructure['sample_description_table'][$i]['data_format']) {
                    case 'mp4a':
                        $ThisFileInfo['fileformat'] = 'mp4';
                        $ThisFileInfo['mime_type'] = 'audio/mp4';
                        unset($ThisFileInfo['video']['dataformat']);
                        break;
                    default:
                        // do nothing
                        break;
                }
                unset($atomstructure['sample_description_table'][$i]['data']);
            }
            break;
        case 'stts':
            // Sample Table Time-to-Sample atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $sttsEntriesDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['time_to_sample_table'][$i]['sample_count'] = BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4));
                $sttsEntriesDataOffset += 4;
                $atomstructure['time_to_sample_table'][$i]['sample_duration'] = BigEndian2Int(substr($atomdata, $sttsEntriesDataOffset, 4));
                $sttsEntriesDataOffset += 4;
            }
            break;
        case 'stss':
            // Sample Table Sync Sample (key frames) atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $stssEntriesDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['time_to_sample_table'][$i] = BigEndian2Int(substr($atomdata, $stssEntriesDataOffset, 4));
                $stssEntriesDataOffset += 4;
            }
            break;
        case 'stsc':
            // Sample Table Sample-to-Chunk atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $stscEntriesDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['sample_to_chunk_table'][$i]['first_chunk'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
                $stscEntriesDataOffset += 4;
                $atomstructure['sample_to_chunk_table'][$i]['samples_per_chunk'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
                $stscEntriesDataOffset += 4;
                $atomstructure['sample_to_chunk_table'][$i]['sample_description'] = BigEndian2Int(substr($atomdata, $stscEntriesDataOffset, 4));
                $stscEntriesDataOffset += 4;
            }
            break;
        case 'stsz':
            // Sample Table SiZe atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['sample_size'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 8, 4));
            $stszEntriesDataOffset = 12;
            if ($atomstructure['sample_size'] == 0) {
                for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                    $atomstructure['sample_size_table'][$i] = BigEndian2Int(substr($atomdata, $stszEntriesDataOffset, 4));
                    $stszEntriesDataOffset += 4;
                }
            }
            break;
        case 'stco':
            // Sample Table Chunk Offset atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $stcoEntriesDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['chunk_offset_table'][$i] = BigEndian2Int(substr($atomdata, $stcoEntriesDataOffset, 4));
                $stcoEntriesDataOffset += 4;
            }
            break;
        case 'dref':
            // Data REFerence atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            $drefDataOffset = 8;
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['data_references'][$i]['size'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 4));
                $drefDataOffset += 4;
                $atomstructure['data_references'][$i]['type'] = substr($atomdata, $drefDataOffset, 4);
                $drefDataOffset += 4;
                $atomstructure['data_references'][$i]['version'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 1));
                $drefDataOffset += 1;
                $atomstructure['data_references'][$i]['flags_raw'] = BigEndian2Int(substr($atomdata, $drefDataOffset, 3));
                // hardcoded: 0x000
                $drefDataOffset += 3;
                $atomstructure['data_references'][$i]['data'] = substr($atomdata, $drefDataOffset, $atomstructure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
                $drefDataOffset += $atomstructure['data_references'][$i]['size'] - 4 - 4 - 1 - 3;
                $atomstructure['data_references'][$i]['flags']['self_reference'] = (bool) ($atomstructure['data_references'][$i]['flags_raw'] & 0x1);
            }
            break;
        case 'gmin':
            // base Media INformation atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['graphics_mode'] = BigEndian2Int(substr($atomdata, 4, 2));
            $atomstructure['opcolor_red'] = BigEndian2Int(substr($atomdata, 6, 2));
            $atomstructure['opcolor_green'] = BigEndian2Int(substr($atomdata, 8, 2));
            $atomstructure['opcolor_blue'] = BigEndian2Int(substr($atomdata, 10, 2));
            $atomstructure['balance'] = BigEndian2Int(substr($atomdata, 12, 2));
            $atomstructure['reserved'] = BigEndian2Int(substr($atomdata, 14, 2));
            break;
        case 'smhd':
            // Sound Media information HeaDer atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['balance'] = BigEndian2Int(substr($atomdata, 4, 2));
            $atomstructure['reserved'] = BigEndian2Int(substr($atomdata, 6, 2));
            break;
        case 'vmhd':
            // Video Media information HeaDer atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            $atomstructure['graphics_mode'] = BigEndian2Int(substr($atomdata, 4, 2));
            $atomstructure['opcolor_red'] = BigEndian2Int(substr($atomdata, 6, 2));
            $atomstructure['opcolor_green'] = BigEndian2Int(substr($atomdata, 8, 2));
            $atomstructure['opcolor_blue'] = BigEndian2Int(substr($atomdata, 10, 2));
            $atomstructure['flags']['no_lean_ahead'] = (bool) ($atomstructure['flags_raw'] & 0x1);
            break;
        case 'hdlr':
            // HanDLeR reference atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['component_type'] = substr($atomdata, 4, 4);
            $atomstructure['component_subtype'] = substr($atomdata, 8, 4);
            $atomstructure['component_manufacturer'] = substr($atomdata, 12, 4);
            $atomstructure['component_flags_raw'] = BigEndian2Int(substr($atomdata, 16, 4));
            $atomstructure['component_flags_mask'] = BigEndian2Int(substr($atomdata, 20, 4));
            $atomstructure['component_name'] = Pascal2String(substr($atomdata, 24));
            break;
        case 'mdhd':
            // MeDia HeaDer atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4));
            $atomstructure['time_scale'] = BigEndian2Int(substr($atomdata, 12, 4));
            $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 16, 4));
            $atomstructure['language_id'] = BigEndian2Int(substr($atomdata, 20, 2));
            $atomstructure['quality'] = BigEndian2Int(substr($atomdata, 22, 2));
            if ($atomstructure['time_scale'] == 0) {
                $ThisFileInfo['error'] .= "\n" . 'Corrupt Quicktime file: mdhd.time_scale == zero';
                return false;
            }
            $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']);
            $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']);
            $atomstructure['playtime_seconds'] = $atomstructure['duration'] / $atomstructure['time_scale'];
            $atomstructure['language'] = QuicktimeLanguageLookup($atomstructure['language_id']);
            break;
        case 'pnot':
            // Preview atom
            $atomstructure['modification_date'] = BigEndian2Int(substr($atomdata, 0, 4));
            // "standard Macintosh format"
            $atomstructure['version_number'] = BigEndian2Int(substr($atomdata, 4, 2));
            // hardcoded: 0x00
            $atomstructure['atom_type'] = substr($atomdata, 6, 4);
            // usually: 'PICT'
            $atomstructure['atom_index'] = BigEndian2Int(substr($atomdata, 10, 2));
            // usually: 0x01
            $atomstructure['modification_date_unix'] = DateMac2Unix($atomstructure['modification_date']);
            break;
        case 'crgn':
            // Clipping ReGioN atom
            $atomstructure['region_size'] = BigEndian2Int(substr($atomdata, 0, 2));
            // The Region size, Region boundary box,
            $atomstructure['boundary_box'] = BigEndian2Int(substr($atomdata, 2, 8));
            // and Clipping region data fields
            $atomstructure['clipping_data'] = substr($atomdata, 10);
            // constitute a QuickDraw region.
            break;
        case 'load':
            // track LOAD settings atom
            $atomstructure['preload_start_time'] = BigEndian2Int(substr($atomdata, 0, 4));
            $atomstructure['preload_duration'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['preload_flags_raw'] = BigEndian2Int(substr($atomdata, 8, 4));
            $atomstructure['default_hints_raw'] = BigEndian2Int(substr($atomdata, 12, 4));
            $atomstructure['default_hints']['double_buffer'] = (bool) ($atomstructure['default_hints_raw'] & 0x20);
            $atomstructure['default_hints']['high_quality'] = (bool) ($atomstructure['default_hints_raw'] & 0x100);
            break;
        case 'tmcd':
            // TiMe CoDe atom
        // TiMe CoDe atom
        case 'chap':
            // CHAPter list atom
        // CHAPter list atom
        case 'sync':
            // SYNChronization atom
        // SYNChronization atom
        case 'scpt':
            // tranSCriPT atom
        // tranSCriPT atom
        case 'ssrc':
            // non-primary SouRCe atom
            for ($i = 0; $i < strlen($atomdata) % 4; $i++) {
                $atomstructure['track_id'][$i] = BigEndian2Int(substr($atomdata, $i * 4, 4));
            }
            break;
        case 'elst':
            // Edit LiST atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['number_entries'] = BigEndian2Int(substr($atomdata, 4, 4));
            for ($i = 0; $i < $atomstructure['number_entries']; $i++) {
                $atomstructure['edit_list'][$i]['track_duration'] = BigEndian2Int(substr($atomdata, 8 + $i * 12 + 0, 4));
                $atomstructure['edit_list'][$i]['media_time'] = BigEndian2Int(substr($atomdata, 8 + $i * 12 + 4, 4));
                $atomstructure['edit_list'][$i]['media_rate'] = BigEndian2Int(substr($atomdata, 8 + $i * 12 + 8, 4));
            }
            break;
        case 'kmat':
            // compressed MATte atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            // hardcoded: 0x000
            $atomstructure['matte_data_raw'] = substr($atomdata, 4);
            break;
        case 'ctab':
            // Color TABle atom
            $atomstructure['color_table_seed'] = BigEndian2Int(substr($atomdata, 0, 4));
            // hardcoded: 0x00000000
            $atomstructure['color_table_flags'] = BigEndian2Int(substr($atomdata, 4, 2));
            // hardcoded: 0x8000
            $atomstructure['color_table_size'] = BigEndian2Int(substr($atomdata, 6, 2)) + 1;
            for ($colortableentry = 0; $colortableentry < $atomstructure['color_table_size']; $colortableentry++) {
                $atomstructure['color_table'][$colortableentry]['alpha'] = BigEndian2Int(substr($atomdata, 8 + $colortableentry * 8 + 0, 2));
                $atomstructure['color_table'][$colortableentry]['red'] = BigEndian2Int(substr($atomdata, 8 + $colortableentry * 8 + 2, 2));
                $atomstructure['color_table'][$colortableentry]['green'] = BigEndian2Int(substr($atomdata, 8 + $colortableentry * 8 + 4, 2));
                $atomstructure['color_table'][$colortableentry]['blue'] = BigEndian2Int(substr($atomdata, 8 + $colortableentry * 8 + 6, 2));
            }
            break;
        case 'mvhd':
            // MoVie HeaDer atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4));
            $atomstructure['time_scale'] = BigEndian2Int(substr($atomdata, 12, 4));
            $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 16, 4));
            $atomstructure['preferred_rate'] = FixedPoint16_16(substr($atomdata, 20, 4));
            $atomstructure['preferred_volume'] = FixedPoint8_8(substr($atomdata, 24, 2));
            $atomstructure['reserved'] = substr($atomdata, 26, 10);
            $atomstructure['matrix_a'] = FixedPoint16_16(substr($atomdata, 36, 4));
            $atomstructure['matrix_b'] = FixedPoint16_16(substr($atomdata, 40, 4));
            $atomstructure['matrix_u'] = FixedPoint16_16(substr($atomdata, 44, 4));
            $atomstructure['matrix_c'] = FixedPoint16_16(substr($atomdata, 48, 4));
            $atomstructure['matrix_v'] = FixedPoint16_16(substr($atomdata, 52, 4));
            $atomstructure['matrix_d'] = FixedPoint16_16(substr($atomdata, 56, 4));
            $atomstructure['matrix_x'] = FixedPoint2_30(substr($atomdata, 60, 4));
            $atomstructure['matrix_y'] = FixedPoint2_30(substr($atomdata, 64, 4));
            $atomstructure['matrix_w'] = FixedPoint2_30(substr($atomdata, 68, 4));
            $atomstructure['preview_time'] = BigEndian2Int(substr($atomdata, 72, 4));
            $atomstructure['preview_duration'] = BigEndian2Int(substr($atomdata, 76, 4));
            $atomstructure['poster_time'] = BigEndian2Int(substr($atomdata, 80, 4));
            $atomstructure['selection_time'] = BigEndian2Int(substr($atomdata, 84, 4));
            $atomstructure['selection_duration'] = BigEndian2Int(substr($atomdata, 88, 4));
            $atomstructure['current_time'] = BigEndian2Int(substr($atomdata, 92, 4));
            $atomstructure['next_track_id'] = BigEndian2Int(substr($atomdata, 96, 4));
            if ($atomstructure['time_scale'] == 0) {
                $ThisFileInfo['error'] .= "\n" . 'Corrupt Quicktime file: mvhd.time_scale == zero';
                return false;
            }
            $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']);
            $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']);
            $ThisFileInfo['quicktime']['time_scale'] = $atomstructure['time_scale'];
            $ThisFileInfo['playtime_seconds'] = $atomstructure['duration'] / $atomstructure['time_scale'];
            break;
        case 'tkhd':
            // TracK HeaDer atom
            $atomstructure['version'] = BigEndian2Int(substr($atomdata, 0, 1));
            $atomstructure['flags_raw'] = BigEndian2Int(substr($atomdata, 1, 3));
            $atomstructure['creation_time'] = BigEndian2Int(substr($atomdata, 4, 4));
            $atomstructure['modify_time'] = BigEndian2Int(substr($atomdata, 8, 4));
            $atomstructure['trackid'] = BigEndian2Int(substr($atomdata, 12, 4));
            $atomstructure['reserved1'] = BigEndian2Int(substr($atomdata, 16, 4));
            $atomstructure['duration'] = BigEndian2Int(substr($atomdata, 20, 4));
            $atomstructure['reserved2'] = BigEndian2Int(substr($atomdata, 24, 8));
            $atomstructure['layer'] = BigEndian2Int(substr($atomdata, 32, 2));
            $atomstructure['alternate_group'] = BigEndian2Int(substr($atomdata, 34, 2));
            $atomstructure['volume'] = FixedPoint8_8(substr($atomdata, 36, 2));
            $atomstructure['reserved3'] = BigEndian2Int(substr($atomdata, 38, 2));
            $atomstructure['matrix_a'] = FixedPoint16_16(substr($atomdata, 40, 4));
            $atomstructure['matrix_b'] = FixedPoint16_16(substr($atomdata, 44, 4));
            $atomstructure['matrix_u'] = FixedPoint16_16(substr($atomdata, 48, 4));
            $atomstructure['matrix_c'] = FixedPoint16_16(substr($atomdata, 52, 4));
            $atomstructure['matrix_v'] = FixedPoint16_16(substr($atomdata, 56, 4));
            $atomstructure['matrix_d'] = FixedPoint16_16(substr($atomdata, 60, 4));
            $atomstructure['matrix_x'] = FixedPoint2_30(substr($atomdata, 64, 4));
            $atomstructure['matrix_y'] = FixedPoint2_30(substr($atomdata, 68, 4));
            $atomstructure['matrix_w'] = FixedPoint2_30(substr($atomdata, 72, 4));
            $atomstructure['width'] = FixedPoint16_16(substr($atomdata, 76, 4));
            $atomstructure['height'] = FixedPoint16_16(substr($atomdata, 80, 4));
            $atomstructure['flags']['enabled'] = (bool) ($atomstructure['flags_raw'] & 0x1);
            $atomstructure['flags']['in_movie'] = (bool) ($atomstructure['flags_raw'] & 0x2);
            $atomstructure['flags']['in_preview'] = (bool) ($atomstructure['flags_raw'] & 0x4);
            $atomstructure['flags']['in_poster'] = (bool) ($atomstructure['flags_raw'] & 0x8);
            $atomstructure['creation_time_unix'] = DateMac2Unix($atomstructure['creation_time']);
            $atomstructure['modify_time_unix'] = DateMac2Unix($atomstructure['modify_time']);
            if (!isset($ThisFileInfo['video']['resolution_x']) || !isset($ThisFileInfo['video']['resolution_y'])) {
                $ThisFileInfo['video']['resolution_x'] = $atomstructure['width'];
                $ThisFileInfo['video']['resolution_y'] = $atomstructure['height'];
            }
            $ThisFileInfo['video']['resolution_x'] = max($ThisFileInfo['video']['resolution_x'], $atomstructure['width']);
            $ThisFileInfo['video']['resolution_y'] = max($ThisFileInfo['video']['resolution_y'], $atomstructure['height']);
            if (!empty($ThisFileInfo['video']['resolution_x']) && !empty($ThisFileInfo['video']['resolution_y'])) {
                $ThisFileInfo['quicktime']['video']['resolution_x'] = $ThisFileInfo['video']['resolution_x'];
                $ThisFileInfo['quicktime']['video']['resolution_y'] = $ThisFileInfo['video']['resolution_y'];
            } else {
                unset($ThisFileInfo['video']['resolution_x']);
                unset($ThisFileInfo['video']['resolution_y']);
                unset($ThisFileInfo['quicktime']['video']);
            }
            break;
        case 'mdat':
            // Media DATa atom
        // Media DATa atom
        case 'free':
            // FREE space atom
        // FREE space atom
        case 'skip':
            // SKIP atom
        // SKIP atom
        case 'wide':
            // 64-bit expansion placeholder atom
            // 'mdat' data is too big to deal with, contains no useful metadata
            // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
            // When writing QuickTime files, it is sometimes necessary to update an atom's size.
            // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
            // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
            // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
            // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
            // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
            // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
            break;
        default:
            $ThisFileInfo['warning'] .= "\n" . 'Unknown QuickTime atom type: "' . $atomname . '" at offset ' . $baseoffset;
            $atomstructure['data'] = $atomdata;
            break;
    }
    array_pop($atomHierarchy);
    return $atomstructure;
}
Example #2
0
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $Original['avdataoffset'] = $ThisFileInfo['avdataoffset'];
    $Original['avdataend'] = $ThisFileInfo['avdataend'];
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'FORM':
            $ThisFileInfo['fileformat'] = 'aiff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            break;
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        case 'RMP3':
            // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
            $RIFFtype = substr($RIFFheader, 8, 4);
            if ($RIFFtype == 'RMP3') {
                $RIFFtype == 'WAVE';
            }
            $ThisFileInfo['fileformat'] = 'riff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF']["{$RIFFtype}"] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            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':
        case 'RMP3':
            // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
            if (empty($ThisFileInfo['audio']['bitrate_mode'])) {
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            if (empty($ThisFileInfo['audio']['dataformat'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wav';
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['size'];
            }
            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]);
                if (substr($ThisFileInfo['audio']['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                    $ThisFileInfo['warning'] .= "\n" . 'Audio codec = ' . $ThisFileInfo['audio']['codec'];
                }
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                if ($ThisFileInfo['audio']['bits_per_sample'] == 0) {
                    unset($ThisFileInfo['audio']['bits_per_sample']);
                }
                $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'])) {
                    $ThisFileInfo['audio']['lossless'] = false;
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 1:
                            // PCM
                            $ThisFileInfo['audio']['lossless'] = true;
                            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'] = EitherEndian2Int($ThisFileInfo, substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, 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['RIFF']['WAVE']['bext'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 0, 256));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 256, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reference'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 288, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 320, 10);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 330, 8);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['time_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 338, 8));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['bwf_version'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 346, 1));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reserved'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 347, 254));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['coding_history'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 601)));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date_unix'] = mktime(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 0, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 3, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 6, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 5, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 8, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 0, 4));
                $ThisFileInfo['RIFF']['comments']['author'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'];
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 0, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x1);
                if ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous']) {
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['padding'] = InverseBoolean($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x2);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['22_or_44'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x4);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['free_format'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x8);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['nominal_frame_size'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 2, 2));
                }
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['anciliary_data_length'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 6, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 8, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_left'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x1);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_free'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x2);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_right'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x4);
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['version'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 0, 4);
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 4, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 68, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['cut_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 132, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['client_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 196, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['category'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 260, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['classification'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 324, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['out_cue'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 388, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 452, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 462, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 470, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 480, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 488, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_version'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 552, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['user_defined_text'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 616, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['zero_db_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 680, 4), true);
                for ($i = 0; $i < 8; $i++) {
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['usage_fourcc'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8, 4);
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['timer_value'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8 + 4, 4));
                }
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['url'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 748, 1024));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['tag_text'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 1772)));
                $ThisFileInfo['RIFF']['comments']['artist'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'];
            }
            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']);
            }
            if (!empty($ThisFileInfo['wavpack'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wavpack';
                $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
                $ThisFileInfo['audio']['encoder'] = 'WavPack v' . $ThisFileInfo['wavpack']['version'];
                // Reset to the way it was - RIFF parsing will have messed this up
                $ThisFileInfo['avdataend'] = $Original['avdataend'];
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
                fseek($fd, $ThisFileInfo['avdataoffset'] - 44, SEEK_SET);
                $RIFFdata = fread($fd, 44);
                $OrignalRIFFheaderSize = LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                $OrignalRIFFdataSize = LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                    $ThisFileInfo['avdataend'] -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                    fseek($fd, $ThisFileInfo['avdataend'], SEEK_SET);
                    $RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                }
                // move the data chunk after all other chunks (if any)
                // so that the RIFF parser doesn't see EOF when trying
                // to skip over the data chunk
                $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                ParseRIFFdata($RIFFdata, $ThisFileInfo);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['size'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = EitherEndian2Int($ThisFileInfo, 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);
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                $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]);
                                        $ThisFileInfo['audio']['lossless'] = false;
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 1:
                                                // PCM
                                                $ThisFileInfo['audio']['lossless'] = true;
                                                break;
                                            case 85:
                                                // MPEG Layer 3
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                // AC-3
                                                $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'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = EitherEndian2Int($ThisFileInfo, 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 ($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']) {
                                            case 'HFYU':
                                                // Huffman Lossless Codec
                                            // Huffman Lossless Codec
                                            case 'IRAW':
                                                // Intel YUV Uncompressed
                                            // Intel YUV Uncompressed
                                            case 'YUY2':
                                                // Uncompressed YUV 4:2:2
                                                $ThisFileInfo['video']['lossless'] = true;
                                                break;
                                            default:
                                                $ThisFileInfo['video']['lossless'] = false;
                                                break;
                                        }
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = EitherEndian2Int($ThisFileInfo, 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'] = EitherEndian2Int($ThisFileInfo, 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
                                                $ThisFileInfo['video']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'];
                                                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'];
                            switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) {
                                case 'HFYU':
                                    // Huffman Lossless Codec
                                // Huffman Lossless Codec
                                case 'IRAW':
                                    // Intel YUV Uncompressed
                                // Intel YUV Uncompressed
                                case 'YUY2':
                                    // Uncompressed YUV 4:2:2
                                    $ThisFileInfo['video']['lossless'] = true;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                                default:
                                    $ThisFileInfo['video']['lossless'] = false;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                            }
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            $ThisFileInfo['audio']['lossless'] = true;
            unset($ThisFileInfo['mime_type']);
            $ThisFileInfo['avdataoffset'] = 44;
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = EitherEndian2Int($ThisFileInfo, 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;
        case 'AIFF':
        case 'AIFC':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'aiff';
            $ThisFileInfo['audio']['lossless'] = true;
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    if ($ThisFileInfo['avdataend'] == $ThisFileInfo['filesize'] + 1 && $ThisFileInfo['filesize'] % 2 == 1) {
                        // structures rounded to 2-byte boundary, but dumb encoders
                        // forget to pad end of file to make this actually work
                    } else {
                        $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                    }
                    $ThisFileInfo['avdataend'] = $ThisFileInfo['filesize'];
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'])) {
                $ThisFileInfo['RIFF']['audio']['channels'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 0, 2), true);
                $ThisFileInfo['RIFF']['audio']['total_samples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 2, 4), false);
                $ThisFileInfo['RIFF']['audio']['bits_per_sample'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 6, 2), true);
                $ThisFileInfo['RIFF']['audio']['sample_rate'] = (int) BigEndian2Float(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 8, 10));
                if ($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['size'] > 18) {
                    $ThisFileInfo['RIFF']['audio']['codec_fourcc'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 18, 4);
                    $CodecNameSize = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 22, 1), false);
                    $ThisFileInfo['RIFF']['audio']['codec_name'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 23, $CodecNameSize);
                    if ($ThisFileInfo['RIFF']['audio']['codec_name'] == 'NONE') {
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                    } else {
                        $ThisFileInfo['audio']['codec'] = $ThisFileInfo['RIFF']['audio']['codec_name'];
                        $ThisFileInfo['audio']['lossless'] = false;
                    }
                }
                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['RIFF']['audio']['channels'];
                if ($ThisFileInfo['RIFF']['audio']['bits_per_sample'] > 0) {
                    $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['audio']['bits_per_sample'];
                }
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF']['audio']['sample_rate'];
                if ($ThisFileInfo['audio']['sample_rate'] == 0) {
                    $ThisFileInfo['error'] .= "\n" . 'Corrupted AIFF file: sample_rate == zero';
                    return false;
                }
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['audio']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'])) {
                $offset = 0;
                $CommentCount = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                $offset += 2;
                for ($i = 0; $i < $CommentCount; $i++) {
                    $ThisFileInfo['comments_raw'][$i]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 4), false);
                    $offset += 4;
                    $ThisFileInfo['comments_raw'][$i]['marker_id'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), true);
                    $offset += 2;
                    $CommentLength = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                    $offset += 2;
                    $ThisFileInfo['comments_raw'][$i]['comment'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, $CommentLength);
                    $offset += $CommentLength;
                    $ThisFileInfo['comments_raw'][$i]['timestamp_unix'] = DateMac2Unix($ThisFileInfo['comments_raw'][$i]['timestamp']);
                    $ThisFileInfo['RIFF']['comments']['comment'][] = $ThisFileInfo['comments_raw'][$i]['comment'];
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            break;
        case '8SVX':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = '8svx';
            $ThisFileInfo['audio']['bits_per_sample'] = 8;
            $ThisFileInfo['audio']['channels'] = 1;
            // overridden below, if need be
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['offset'])) {
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['oneShotHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 0, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['repeatHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 4, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerHiCycle'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 8, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 12, 2));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['ctOctave'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 14, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 15, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['Volume'] = FixedPoint16_16(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 16, 4));
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'];
                switch ($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression']) {
                    case 0:
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                        $ActualBitsPerSample = 8;
                        break;
                    case 1:
                        $ThisFileInfo['audio']['codec'] = 'Fibonacci-delta encoding';
                        $ThisFileInfo['audio']['lossless'] = false;
                        $ActualBitsPerSample = 4;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                        break;
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'])) {
                $ChannelsIndex = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'], 0, 4));
                switch ($ChannelsIndex) {
                    case 6:
                        // Stereo
                        $ThisFileInfo['audio']['channels'] = 2;
                        break;
                    case 2:
                        // Left channel only
                    // Left channel only
                    case 4:
                        // Right channel only
                        $ThisFileInfo['audio']['channels'] = 1;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                        break;
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ActualBitsPerSample * $ThisFileInfo['audio']['channels'];
            if (!empty($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / ($ThisFileInfo['audio']['bitrate'] / 8);
            }
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|), found "' . $arraykeys[0] . '" instead';
            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', 'ISFT' => 'encoded_by');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"])) {
                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, false, true);
    }
    if (empty($ThisFileInfo['audio']['encoder']) && !empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
        $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
    }
    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['RIFF']['raw']['fmt ']['nBitsPerSample'] > 0) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    return true;
}