以前在手机上用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 - /******************************************************************************
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 - /******************************************************************************
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()); }
|