novesky的个人主页

http://www.qtcn.org/bbs/u/73156  [收藏] [复制]

novesky

  • 16

    关注

  • 37

    粉丝

  • 188

    访客

  • 等级:侠客
  • 总积分:130
  • 男,2011-11-16

最后登录:2016-01-11

更多资料

日志

flash文件头的解析

2011-12-24 16:06
     以前在手机上用qt做过一个基于libflash的flash播放器,现在项目里播放功能用其他方案,但是要知道flash文件播放的帧数和帧率等参数,直接把libflash搬过来有点太夸张了,所以还是自己分析二进制文件吧

    flash文件头的结构参考http://sealbird.iteye.com/blog/1258904
    由于手头上flash文件不多,试过 压缩过的flash10文件,正常。对于解压部分提供了2种选择,即zlib和qUncompress。qUncompress的话若不是解压用qCompress压缩的数据,则要在头部加入4个字节的解压后长度信息。
    文件头中rect数据段的各参数读取最麻烦,要一位位读取,而不是平时用的字节为单位,而且有多少为还不是固定的。这里用了标准库里的std::bitset来存取这些数据,蛮方便。话说 QBitArray竟然没提供像std::bitset的to_ulong()这样实用的函数,那这个QBitArray有什么用我还真想不出。std::bitset有点不好,就是它是个模板,大小要预先定好。QBitArray可以动态分配大小,就缺一个转换到整型的函数,否则就用它了。
    话说这么个简单的东西也写得我蛮累的,囧。直接上代码吧

头文件qflashinfo.h
  1. /******************************************************************************
        QFlashInfo: read flash information from file head
        Copyright (C) 2011 Wang Bin <wbsecg1@gmail.com>
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
        You should have received a copy of the GNU General Public License along
        with this program; if not, write to the Free Software Foundation, Inc.,
        51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    ******************************************************************************/
    #ifndef QFLASHINFO_H
    #define QFLASHINFO_H
    #include <QtCore/QString>
    class QFlashInfo
    {
    public:
        QFlashInfo(const QString& fileName);
        bool parse();
        int getPlayTimeUSec() const;
        int getTotalFrames() const;
        float getFrameRate() const;
        void showInfo();
    private:
        QString file_name;                // SWF file analyzed
        QByteArray magic;                // Magic in a SWF file (FWS or CWS)
        bool compressed;        // Flag to indicate a compressed file (CWS)
        char version;            // Flash version
        size_t file_size, uncompressed_size;        // Uncompressed file size (in bytes)
        int xmin, xmax, ymin, ymax; //Rect. width = xmax - xmin, height = ymax - ymin
        int width;                // Flash movie native width
        int height;                // Flash movie native height
        float frame_rate;
        bool valid;                // Valid SWF file
        int frames;                // Flash movie total frames
    };
    #endif // QFLASHINFO_H
源文件qflashinfo.cpp
  1. /******************************************************************************
        QFlashInfo: read flash information from file head
        Copyright (C) 2011 Wang Bin <wbsecg1@gmail.com>
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
        You should have received a copy of the GNU General Public License along
        with this program; if not, write to the Free Software Foundation, Inc.,
        51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    ******************************************************************************/
    #include "qflashinfo.h"
    #define USE_ZLIB 0
    #include <bitset>
    #include <QtCore/QByteArray>
    #include <QtCore/QFile>
    #include <QtDebug>
    #if USE_ZLIB
    #include <zlib.h>
    #endif //USE_ZLIB

    QFlashInfo::QFlashInfo(const QString& fileName)
        :file_name(fileName)
    {
        valid = compressed = false;
        file_size = uncompressed_size = 0;
        xmin = xmax = ymin = ymax =0;
        width = height = 0;
        frames = 0;
        frame_rate = 0.;
    }
    bool QFlashInfo::parse()
    {
        QFile file(file_name);
        if (!file.open(QIODevice::ReadOnly)) {
            qDebug("Failed to open %s: %s", qPrintable(file_name), qPrintable(file.errorString()));
            return false;
        }
        file_size = file.size();
        magic = file.read(3);
        if (magic != "FWS" && magic != "CWS") {
            valid =  false;
            return valid;
        }
        //CWS: data from the 9th byte are compressed by zlib
        compressed = (magic[0] == 'C');
        version = file.read(1)[0] & 0xff; //not toInt(), why?
    /*!
        FWS: size == file size
        CWS: size == file uncompressed size
    */
        uncompressed_size = 0 ;
        for (int i=0; i<4; ++i) {
            char t = file.read(1)[0];
            int s = t & 0xff;
            //s = file.read(1).toInt(); //?
            uncompressed_size += (s << (i << 3)) ;
        }
        // RECT
        QByteArray buffer = file.read(file_size - 8);
        QByteArray *uncompressed_data = &buffer;
        file.close();
    #if USE_ZLIB
        if (compressed) {
            ulong len = uncompressed_size - 8 ;
            uncompressed_data = new QByteArray(len, 0);
            // First decompress GZ stream
            int res = uncompress((Bytef*)uncompressed_data->data(), (uLongf*)&uncompressed_size, (Bytef*)buffer.constData(), file_size - 8);
            switch (res)    {
            case Z_MEM_ERROR: printf("Z_MEM_ERROR\n"); break;
            case Z_BUF_ERROR: printf("Z_BUF_ERROR\n"); break;
            case Z_DATA_ERROR: printf("Z_DATA_ERROR\n"); break;
            }
        }
    #else
        if (compressed) {
            file.open(QIODevice::ReadOnly);
            buffer.clear();
            buffer = file.readAll();
            file.close();
            buffer.remove(0, 4);
            ulong len = uncompressed_size - 8 ;
            buffer[0] = (len & 0xff000000) >> 24;
            buffer[1] = (len & 0x00ff0000) >> 16;
            buffer[2] = (len & 0x0000ff00) >> 8;
            buffer[3] = (len & 0x000000ff);
            uncompressed_data = new QByteArray(qUncompress(buffer));
        }
    #endif //USE_ZLIB
        char *p_data = uncompressed_data->data();
        //The first 5 is the bits of he next 4 point store
        int bits_per_value = *p_data & 0xff;
        bits_per_value >>= 3; //RECT field size //bits
        bits_per_value &= 0xff;
        printf("bits per point: %d\n", bits_per_value);
        std::bitset<32> rect_point; //32?
        //read bit by bit.
        int t = (*p_data & 0xff);
        int byte_current = (t << 5) & 0xff;
        // Current bit (first byte starts off already shifted)
        int bits_remain = 2;
        //get all 4 values in the RECT
        for (int i = 0; i<4; ++i) {
            int bit_index = 0;
            while (bit_index < bits_per_value) {
                rect_point[bit_index] = byte_current & 128; //1000000, get the highest bit
                ++bit_index;
                byte_current <<= 1;
                --bits_remain;
                // We will be needing a new byte if we run out of bits
                if (bits_remain < 0) {
                    byte_current = (int)(0xff & *++p_data);
                    bits_remain = 7;
                }
            }
            int value = rect_point.to_ulong();
            printf("bits %6d: %s\n", value, rect_point.to_string().c_str());
            rect_point.reset();
            switch (i) {
            case 0: xmin = value; break;
            case 1: xmax = value; break;
            case 2: ymin = value; break;
            case 3: ymax = value; break;
            }
        }
        // Frame rate
        int fractional_hex = (int)(*++p_data);
        int integer_hex = (int)(*++p_data);
        frame_rate = integer_hex + (float)fractional_hex/(float)(1<<8);
        // Frames. Little-Endian
        frames = 0xff & *++p_data;
        frames += (int)(0xff & *++p_data) << 8;
        valid = true;
        return valid ;
    }
    int QFlashInfo::getPlayTimeUSec() const
    {
        return (frames * 1000)/frame_rate;
    }
    int QFlashInfo::getTotalFrames() const
    {
        return frames;
    }
    float QFlashInfo::getFrameRate() const
    {
        return frame_rate;
    }

    void QFlashInfo::showInfo()
    {
        printf("File: %s. Is valid swf: %d\n"
               "Magic: %s. Compressed: %d. Version: %d\n"
               "File size: %d. Uncompressed size: %d\n"
               "x: %d - %d, y: %d - %d\n"
               "width: %d. height: %d\n"
               "Frames: %d. Frame rate: %f(fps). Time: %d(us)\n"
               , qPrintable(file_name), valid
               , magic.constData(), compressed, version
               , file_size, uncompressed_size
               , xmin, xmax, ymin, ymax
               , xmax - xmin, ymax - ymin
               , frames, frame_rate, getPlayTimeUSec());
    }



分类:默认分类|回复:0|浏览:2542|全站可见|转载
 

Powered by phpwind v8.7 Certificate Copyright Time now is:05-02 00:49
©2005-2016 QTCN开发网 版权所有 Gzip disabled