Exemplo n.º 1
0
function getBMPHeaderFilepointer(&$fd, &$ThisFileInfo, $ExtractPalette = false, $ExtractData = false)
{
    $ThisFileInfo['fileformat'] = 'bmp';
    $ThisFileInfo['video']['dataformat'] = 'bmp';
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $offset = 0;
    $BMPheader = fread($fd, 14 + 40);
    // check if the hardcoded-to-1 "planes" is at offset 22 or 26
    $planes22 = LittleEndian2Int(substr($BMPheader, 22, 2));
    $planes26 = LittleEndian2Int(substr($BMPheader, 26, 2));
    if ($planes22 == 1 && $planes26 != 1) {
        $ThisFileInfo['bmp']['type_os'] = 'OS/2';
        $ThisFileInfo['bmp']['type_version'] = 1;
    } elseif ($planes26 == 1 && $planes22 != 1) {
        $ThisFileInfo['bmp']['type_os'] = 'Windows';
        $ThisFileInfo['bmp']['type_version'] = 1;
    } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 12) {
        $ThisFileInfo['bmp']['type_os'] = 'OS/2';
        $ThisFileInfo['bmp']['type_version'] = 1;
    } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 40) {
        $ThisFileInfo['bmp']['type_os'] = 'Windows';
        $ThisFileInfo['bmp']['type_version'] = 1;
    } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 84) {
        $ThisFileInfo['bmp']['type_os'] = 'Windows';
        $ThisFileInfo['bmp']['type_version'] = 4;
    } elseif ($ThisFileInfo['bmp']['header']['raw']['header_size'] == 100) {
        $ThisFileInfo['bmp']['type_os'] = 'Windows';
        $ThisFileInfo['bmp']['type_version'] = 5;
    }
    // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
    // all versions
    // WORD    bfType;
    // DWORD   bfSize;
    // WORD    bfReserved1;
    // WORD    bfReserved2;
    // DWORD   bfOffBits;
    $ThisFileInfo['bmp']['header']['raw']['identifier'] = substr($BMPheader, $offset, 2);
    $offset += 2;
    $ThisFileInfo['bmp']['header']['raw']['filesize'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
    $offset += 4;
    $ThisFileInfo['bmp']['header']['raw']['reserved1'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
    $offset += 2;
    $ThisFileInfo['bmp']['header']['raw']['reserved2'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
    $offset += 2;
    $ThisFileInfo['bmp']['header']['raw']['data_offset'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
    $offset += 4;
    if ($ThisFileInfo['bmp']['type_os'] == 'OS/2') {
        // OS/2-format BMP
        // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
        // DWORD  Size;             /* Size of this structure in bytes */
        // DWORD  Width;            /* Bitmap width in pixels */
        // DWORD  Height;           /* Bitmap height in pixel */
        // WORD   NumPlanes;        /* Number of bit planes (color depth) */
        // WORD   BitsPerPixel;     /* Number of bits per pixel per plane */
        $ThisFileInfo['bmp']['header']['raw']['header_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['width'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['bmp']['header']['raw']['height'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['bmp']['header']['raw']['planes'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['bmp']['header']['raw']['width'];
        $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['bmp']['header']['raw']['height'];
        $ThisFileInfo['video']['codec'] = 'BI_RGB ' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . '-bit';
        if ($ThisFileInfo['bmp']['type_version'] >= 2) {
            // DWORD  Compression;      /* Bitmap compression scheme */
            // DWORD  ImageDataSize;    /* Size of bitmap data in bytes */
            // DWORD  XResolution;      /* X resolution of display device */
            // DWORD  YResolution;      /* Y resolution of display device */
            // DWORD  ColorsUsed;       /* Number of color table indices used */
            // DWORD  ColorsImportant;  /* Number of important color indices */
            // WORD   Units;            /* Type of units used to measure resolution */
            // WORD   Reserved;         /* Pad structure to 4-byte boundary */
            // WORD   Recording;        /* Recording algorithm */
            // WORD   Rendering;        /* Halftoning algorithm used */
            // DWORD  Size1;            /* Reserved for halftoning algorithm use */
            // DWORD  Size2;            /* Reserved for halftoning algorithm use */
            // DWORD  ColorEncoding;    /* Color model used in bitmap */
            // DWORD  Identifier;       /* Reserved for application use */
            $ThisFileInfo['bmp']['header']['raw']['compression'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['bmp_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['resolution_h'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['resolution_v'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['colors_used'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['colors_important'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['resolution_units'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
            $offset += 2;
            $ThisFileInfo['bmp']['header']['raw']['reserved1'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
            $offset += 2;
            $ThisFileInfo['bmp']['header']['raw']['recording'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
            $offset += 2;
            $ThisFileInfo['bmp']['header']['raw']['rendering'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
            $offset += 2;
            $ThisFileInfo['bmp']['header']['raw']['size1'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['size2'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['color_encoding'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['identifier'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['compression'] = BMPcompressionOS2Lookup($ThisFileInfo['bmp']['header']['raw']['compression']);
            $ThisFileInfo['video']['codec'] = $ThisFileInfo['bmp']['header']['compression'] . ' ' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . '-bit';
        }
    } elseif ($ThisFileInfo['bmp']['type_os'] == 'Windows') {
        // Windows-format BMP
        // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
        // all versions
        // DWORD  biSize;
        // LONG   biWidth;
        // LONG   biHeight;
        // WORD   biPlanes;
        // WORD   biBitCount;
        // DWORD  biCompression;
        // DWORD  biSizeImage;
        // LONG   biXPelsPerMeter;
        // LONG   biYPelsPerMeter;
        // DWORD  biClrUsed;
        // DWORD  biClrImportant;
        $ThisFileInfo['bmp']['header']['raw']['header_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['width'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true);
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['height'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true);
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['planes'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] = LittleEndian2Int(substr($BMPheader, $offset, 2));
        $offset += 2;
        $ThisFileInfo['bmp']['header']['raw']['compression'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['bmp_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['resolution_h'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true);
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['resolution_v'] = LittleEndian2Int(substr($BMPheader, $offset, 4), true);
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['colors_used'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['raw']['colors_important'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
        $offset += 4;
        $ThisFileInfo['bmp']['header']['compression'] = BMPcompressionWindowsLookup($ThisFileInfo['bmp']['header']['raw']['compression']);
        $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['bmp']['header']['raw']['width'];
        $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['bmp']['header']['raw']['height'];
        $ThisFileInfo['video']['codec'] = $ThisFileInfo['bmp']['header']['compression'] . ' ' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . '-bit';
        if ($ThisFileInfo['bmp']['type_version'] >= 4) {
            $BMPheader .= fread($fd, 44);
            // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
            // Win95+, WinNT4.0+
            // DWORD        bV4RedMask;
            // DWORD        bV4GreenMask;
            // DWORD        bV4BlueMask;
            // DWORD        bV4AlphaMask;
            // DWORD        bV4CSType;
            // CIEXYZTRIPLE bV4Endpoints;
            // DWORD        bV4GammaRed;
            // DWORD        bV4GammaGreen;
            // DWORD        bV4GammaBlue;
            $ThisFileInfo['bmp']['header']['raw']['red_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['green_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['blue_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['alpha_mask'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['cs_type'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['ciexyz_red'] = substr($BMPheader, $offset, 4);
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['ciexyz_green'] = substr($BMPheader, $offset, 4);
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['ciexyz_blue'] = substr($BMPheader, $offset, 4);
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['gamma_red'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['gamma_green'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['gamma_blue'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['ciexyz_red'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_red']));
            $ThisFileInfo['bmp']['header']['ciexyz_green'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_green']));
            $ThisFileInfo['bmp']['header']['ciexyz_blue'] = FixedPoint2_30(strrev($ThisFileInfo['bmp']['header']['raw']['ciexyz_blue']));
        }
        if ($ThisFileInfo['bmp']['type_version'] >= 5) {
            $BMPheader .= fread($fd, 16);
            // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
            // Win98+, Win2000+
            // DWORD        bV5Intent;
            // DWORD        bV5ProfileData;
            // DWORD        bV5ProfileSize;
            // DWORD        bV5Reserved;
            $ThisFileInfo['bmp']['header']['raw']['intent'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['profile_data_offset'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['profile_data_size'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
            $ThisFileInfo['bmp']['header']['raw']['reserved3'] = LittleEndian2Int(substr($BMPheader, $offset, 4));
            $offset += 4;
        }
    } else {
        $ThisFileInfo['error'] .= "\n" . 'Unknown BMP format in header.';
        return false;
    }
    if ($ExtractPalette || $ExtractData) {
        $PaletteEntries = 0;
        if ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] < 16) {
            $PaletteEntries = pow(2, $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']);
        } elseif (isset($ThisFileInfo['bmp']['header']['raw']['colors_used']) && $ThisFileInfo['bmp']['header']['raw']['colors_used'] > 0 && $ThisFileInfo['bmp']['header']['raw']['colors_used'] <= 256) {
            $PaletteEntries = $ThisFileInfo['bmp']['header']['raw']['colors_used'];
        }
        if ($PaletteEntries > 0) {
            $BMPpalette = fread($fd, 4 * $PaletteEntries);
            $paletteoffset = 0;
            for ($i = 0; $i < $PaletteEntries; $i++) {
                // RGBQUAD          - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
                // BYTE    rgbBlue;
                // BYTE    rgbGreen;
                // BYTE    rgbRed;
                // BYTE    rgbReserved;
                //$ThisFileInfo['bmp']['palette']['blue'][$i]   = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                //$ThisFileInfo['bmp']['palette']['green'][$i] = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                //$ThisFileInfo['bmp']['palette']['red'][$i]  = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                $blue = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                $green = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                $red = LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
                if ($ThisFileInfo['bmp']['type_os'] == 'OS/2' && $ThisFileInfo['bmp']['type_version'] == 1) {
                    // no padding byte
                } else {
                    $paletteoffset++;
                    // padding byte
                }
                $ThisFileInfo['bmp']['palette'][$i] = $red << 16 | $green << 8 | $blue;
            }
        }
    }
    if ($ExtractData) {
        fseek($fd, $ThisFileInfo['bmp']['header']['raw']['data_offset'], SEEK_SET);
        $RowByteLength = ceil($ThisFileInfo['bmp']['header']['raw']['width'] * ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8) / 4) * 4;
        // round up to nearest DWORD boundry
        $BMPpixelData = fread($fd, $ThisFileInfo['bmp']['header']['raw']['height'] * $RowByteLength);
        $pixeldataoffset = 0;
        switch ($ThisFileInfo['bmp']['header']['raw']['compression']) {
            case 0:
                // BI_RGB
                switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) {
                    case 1:
                        for ($row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1; $row >= 0; $row--) {
                            for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col = $col) {
                                $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                for ($i = 7; $i >= 0; $i--) {
                                    $paletteindex = ($paletteindexbyte & 0x1 << $i) >> $i;
                                    $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex];
                                    $col++;
                                }
                            }
                            while ($pixeldataoffset % 4 != 0) {
                                // lines are padded to nearest DWORD
                                $pixeldataoffset++;
                            }
                        }
                        break;
                    case 4:
                        for ($row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1; $row >= 0; $row--) {
                            for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col = $col) {
                                $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                for ($i = 1; $i >= 0; $i--) {
                                    $paletteindex = ($paletteindexbyte & 0xf << 4 * $i) >> 4 * $i;
                                    $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex];
                                    $col++;
                                }
                            }
                            while ($pixeldataoffset % 4 != 0) {
                                // lines are padded to nearest DWORD
                                $pixeldataoffset++;
                            }
                        }
                        break;
                    case 8:
                        for ($row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1; $row >= 0; $row--) {
                            for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) {
                                $paletteindex = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex];
                            }
                            while ($pixeldataoffset % 4 != 0) {
                                // lines are padded to nearest DWORD
                                $pixeldataoffset++;
                            }
                        }
                        break;
                    case 24:
                    case 32:
                        for ($row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1; $row >= 0; $row--) {
                            for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) {
                                $blue = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                $green = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                $red = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                if ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] == 32) {
                                    $paletteoffset++;
                                    // filler byte
                                }
                                $ThisFileInfo['bmp']['data'][$row][$col] = $red << 16 | $green << 8 | $blue;
                            }
                            while ($pixeldataoffset % 4 != 0) {
                                // lines are padded to nearest DWORD
                                $pixeldataoffset++;
                            }
                        }
                        break;
                    case 16:
                    default:
                        $ThisFileInfo['error'] .= "\n" . 'Unknown bits-per-pixel value (' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . ') - cannot read pixel data';
                        break;
                }
                break;
            case 1:
                // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
                switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) {
                    case 8:
                        $pixelcounter = 0;
                        while ($pixeldataoffset < strlen($BMPpixelData)) {
                            $firstbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                            $secondbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                            if ($firstbyte == 0) {
                                // escaped/absolute mode - the first byte of the pair can be set to zero to
                                // indicate an escape character that denotes the end of a line, the end of
                                // a bitmap, or a delta, depending on the value of the second byte.
                                switch ($secondbyte) {
                                    case 0:
                                        // end of line
                                        // no need for special processing, just ignore
                                        break;
                                    case 1:
                                        // end of bitmap
                                        $pixeldataoffset = strlen($BMPpixelData);
                                        // force to exit loop just in case
                                        break;
                                    case 2:
                                        // delta - The 2 bytes following the escape contain unsigned values
                                        // indicating the horizontal and vertical offsets of the next pixel
                                        // from the current position.
                                        $colincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                        $rowincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                        $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'] + $colincrement;
                                        $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'] - $rowincrement;
                                        $pixelcounter = $row * $ThisFileInfo['bmp']['header']['raw']['width'] + $col;
                                        break;
                                    default:
                                        // In absolute mode, the first byte is zero and the second byte is a
                                        // value in the range 03H through FFH. The second byte represents the
                                        // number of bytes that follow, each of which contains the color index
                                        // of a single pixel. Each run must be aligned on a word boundary.
                                        for ($i = 0; $i < $secondbyte; $i++) {
                                            $paletteindex = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                            $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'];
                                            $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'];
                                            $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex];
                                            $pixelcounter++;
                                        }
                                        while ($pixeldataoffset % 2 != 0) {
                                            // Each run must be aligned on a word boundary.
                                            $pixeldataoffset++;
                                        }
                                        break;
                                }
                            } else {
                                // encoded mode - the first byte specifies the number of consecutive pixels
                                // to be drawn using the color index contained in the second byte.
                                for ($i = 0; $i < $firstbyte; $i++) {
                                    $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'];
                                    $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'];
                                    $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$secondbyte];
                                    $pixelcounter++;
                                }
                            }
                        }
                        break;
                    default:
                        $ThisFileInfo['error'] .= "\n" . 'Unknown bits-per-pixel value (' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . ') - cannot read pixel data';
                        break;
                }
                break;
            case 2:
                // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
                switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) {
                    case 4:
                        $pixelcounter = 0;
                        while ($pixeldataoffset < strlen($BMPpixelData)) {
                            $firstbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                            $secondbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                            if ($firstbyte == 0) {
                                // escaped/absolute mode - the first byte of the pair can be set to zero to
                                // indicate an escape character that denotes the end of a line, the end of
                                // a bitmap, or a delta, depending on the value of the second byte.
                                switch ($secondbyte) {
                                    case 0:
                                        // end of line
                                        // no need for special processing, just ignore
                                        break;
                                    case 1:
                                        // end of bitmap
                                        $pixeldataoffset = strlen($BMPpixelData);
                                        // force to exit loop just in case
                                        break;
                                    case 2:
                                        // delta - The 2 bytes following the escape contain unsigned values
                                        // indicating the horizontal and vertical offsets of the next pixel
                                        // from the current position.
                                        $colincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                        $rowincrement = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                        $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'] + $colincrement;
                                        $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'] - $rowincrement;
                                        $pixelcounter = $row * $ThisFileInfo['bmp']['header']['raw']['width'] + $col;
                                        break;
                                    default:
                                        // In absolute mode, the first byte is zero. The second byte contains the number
                                        // of color indexes that follow. Subsequent bytes contain color indexes in their
                                        // high- and low-order 4 bits, one color index for each pixel. In absolute mode,
                                        // each run must be aligned on a word boundary.
                                        unset($paletteindexes);
                                        for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
                                            $paletteindexbyte = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
                                            $paletteindexes[] = ($paletteindexbyte & 0xf0) >> 4;
                                            $paletteindexes[] = $paletteindexbyte & 0xf;
                                        }
                                        while ($pixeldataoffset % 2 != 0) {
                                            // Each run must be aligned on a word boundary.
                                            $pixeldataoffset++;
                                        }
                                        foreach ($paletteindexes as $paletteindex) {
                                            $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'];
                                            $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'];
                                            $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindex];
                                            $pixelcounter++;
                                        }
                                        break;
                                }
                            } else {
                                // encoded mode - the first byte of the pair contains the number of pixels to be
                                // drawn using the color indexes in the second byte. The second byte contains two
                                // color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
                                // The first of the pixels is drawn using the color specified by the high-order
                                // 4 bits, the second is drawn using the color in the low-order 4 bits, the third
                                // is drawn using the color in the high-order 4 bits, and so on, until all the
                                // pixels specified by the first byte have been drawn.
                                $paletteindexes[0] = ($secondbyte & 0xf0) >> 4;
                                $paletteindexes[1] = $secondbyte & 0xf;
                                for ($i = 0; $i < $firstbyte; $i++) {
                                    $col = $pixelcounter % $ThisFileInfo['bmp']['header']['raw']['width'];
                                    $row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1 - ($pixelcounter - $col) / $ThisFileInfo['bmp']['header']['raw']['width'];
                                    $ThisFileInfo['bmp']['data'][$row][$col] = $ThisFileInfo['bmp']['palette'][$paletteindexes[$i % 2]];
                                    $pixelcounter++;
                                }
                            }
                        }
                        break;
                    default:
                        $ThisFileInfo['error'] .= "\n" . 'Unknown bits-per-pixel value (' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . ') - cannot read pixel data';
                        break;
                }
                break;
            case 3:
                // BI_BITFIELDS
                switch ($ThisFileInfo['bmp']['header']['raw']['bits_per_pixel']) {
                    case 16:
                    case 32:
                        $redshift = 0;
                        $greenshift = 0;
                        $blueshift = 0;
                        while (($ThisFileInfo['bmp']['header']['raw']['red_mask'] >> $redshift & 0x1) == 0) {
                            $redshift++;
                        }
                        while (($ThisFileInfo['bmp']['header']['raw']['green_mask'] >> $greenshift & 0x1) == 0) {
                            $greenshift++;
                        }
                        while (($ThisFileInfo['bmp']['header']['raw']['blue_mask'] >> $blueshift & 0x1) == 0) {
                            $blueshift++;
                        }
                        for ($row = $ThisFileInfo['bmp']['header']['raw']['height'] - 1; $row >= 0; $row--) {
                            for ($col = 0; $col < $ThisFileInfo['bmp']['header']['raw']['width']; $col++) {
                                $pixelvalue = LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8));
                                $pixeldataoffset += $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] / 8;
                                $red = round((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['red_mask']) >> $redshift) / ($ThisFileInfo['bmp']['header']['raw']['red_mask'] >> $redshift) * 255);
                                $green = round((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['green_mask']) >> $greenshift) / ($ThisFileInfo['bmp']['header']['raw']['green_mask'] >> $greenshift) * 255);
                                $blue = round((($pixelvalue & $ThisFileInfo['bmp']['header']['raw']['blue_mask']) >> $blueshift) / ($ThisFileInfo['bmp']['header']['raw']['blue_mask'] >> $blueshift) * 255);
                                $ThisFileInfo['bmp']['data'][$row][$col] = $red << 16 | $green << 8 | $blue;
                            }
                            while ($pixeldataoffset % 4 != 0) {
                                // lines are padded to nearest DWORD
                                $pixeldataoffset++;
                            }
                        }
                        break;
                    default:
                        $ThisFileInfo['error'] .= "\n" . 'Unknown bits-per-pixel value (' . $ThisFileInfo['bmp']['header']['raw']['bits_per_pixel'] . ') - cannot read pixel data';
                        break;
                }
                break;
            default:
                // unhandled compression type
                $ThisFileInfo['error'] .= "\n" . 'Unknown/unhandled compression type value (' . $ThisFileInfo['bmp']['header']['raw']['compression'] . ') - cannot decompress pixel data';
                break;
        }
    }
    return true;
}
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;
}