Merge pull request #6 from NickJohn547745/feature/parse_bik_file

Feature/parse bik file
This commit is contained in:
Nicholas Johnson 2025-04-23 18:11:15 -04:00 committed by GitHub
commit 9106dc7646
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 688 additions and 94 deletions

View File

@ -16,4 +16,26 @@ struct LumpIndexEntry {
quint32 length; quint32 length;
}; };
// Bink structure definitions
struct BINKRECT {
int Left;
int Top;
int Width;
int Height;
};
struct BINK {
int Width;
int Height;
uint32_t Frames;
uint32_t FrameNum;
uint32_t FrameRate;
uint32_t FrameRateDiv;
uint32_t ReadError;
uint32_t OpenFlags;
BINKRECT FrameRects;
uint32_t NumRects;
uint32_t FrameChangePercent;
};
#endif // D3DBSP_STRUCTS_H #endif // D3DBSP_STRUCTS_H

396
bink.h Normal file
View File

@ -0,0 +1,396 @@
/* xoreos - A reimplementation of BioWare's Aurora engine
*
* xoreos is the legal property of its developers, whose names
* can be found in the AUTHORS file distributed with this source
* distribution.
*
* xoreos 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 3
* of the License, or (at your option) any later version.
*
* xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file
* Decoding RAD Game Tools' Bink videos.
*/
/* Based on the Bink implementation in FFmpeg (<https://ffmpeg.org/)>,
* which is released under the terms of version 2 or later of the GNU
* Lesser General Public License.
*
* The original copyright notes in the files
* - libavformat/bink.c
* - libavcodec/bink.c
* - libavcodec/binkdata.h
* - libavcodec/binkdsp.c
* - libavcodec/binkdsp.h
* - libavcodec/binkaudio.c
* read as follows:
*
* Bink demuxer
* Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
*
* Bink video decoder
* Copyright (c) 2009 Konstantin Shishkov
* Copyright (C) 2011 Peter Ross <pross@xvid.org>
*
* Bink video decoder
* Copyright (C) 2009 Konstantin Shishkov
*
* Bink DSP routines
* Copyright (c) 2009 Konstantin Shishkov
*
* Bink Audio decoder
* Copyright (c) 2007-2011 Peter Ross (pross@xvid.org)
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef VIDEO_BINK_H
#define VIDEO_BINK_H
#include <vector>
#include <memory>
#include "src/common/types.h"
#include "src/common/rational.h"
#include "src/video/decoder.h"
namespace Common {
class SeekableReadStream;
class BitStream;
class Huffman;
class RDFT;
class DCT;
}
namespace Sound {
class PacketizedAudioStream;
}
namespace Video {
/** A decoder for RAD Game Tools' Bink videos. */
class Bink : public VideoDecoder {
public:
Bink(Common::SeekableReadStream *bink);
~Bink();
protected:
void decodeNextTrackFrame(VideoTrack &track);
void checkAudioBuffer(AudioTrack &track, const Common::Timestamp &endTime);
private:
static const int kAudioChannelsMax = 2;
static const int kAudioBlockSizeMax = (kAudioChannelsMax << 11);
enum AudioCodec {
kAudioCodecDCT,
kAudioCodecRDFT
};
/** An audio track. */
struct AudioInfo {
uint16_t flags;
uint32_t sampleRate;
uint8_t channels;
uint32_t outSampleRate;
uint8_t outChannels;
AudioCodec codec;
bool first;
uint32_t frameLen;
uint32_t overlapLen;
uint32_t blockSize;
uint32_t bandCount;
uint32_t *bands;
float root;
float coeffs[16 * kAudioBlockSizeMax];
int16_t prevCoeffs[kAudioBlockSizeMax];
float *coeffsPtr[kAudioChannelsMax];
Common::RDFT *rdft;
Common::DCT *dct;
AudioInfo();
AudioInfo(const AudioInfo &audioInfo) = default;
~AudioInfo();
};
/** A video frame. */
struct VideoFrame {
bool keyFrame;
uint32_t offset;
uint32_t size;
Common::BitStream *bits;
VideoFrame();
VideoFrame(const VideoFrame &videoFrame) = default;
~VideoFrame();
};
std::unique_ptr<Common::SeekableReadStream> _bink;
std::vector<AudioInfo> _audioTracks; ///< All audio tracks.
std::vector<VideoFrame> _frames; ///< All video frames.
uint32_t _audioTrack; ///< Audio track to use.
/** Load a Bink file. */
void load();
class BinkVideoTrack : public FixedRateVideoTrack {
public:
BinkVideoTrack(uint32_t width, uint32_t height, uint32_t frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32_t id);
uint32_t getWidth() const { return _width; }
uint32_t getHeight() const { return _height; }
int getCurFrame() const { return _curFrame; }
int getFrameCount() const { return _frameCount; }
/** Decode a video packet. */
void decodePacket(Graphics::Surface &surface, VideoFrame &frame);
protected:
Common::Rational getFrameRate() const { return _frameRate; }
private:
/** A decoder state. */
struct DecodeContext {
VideoFrame *video;
uint32_t planeIdx;
uint32_t blockX;
uint32_t blockY;
byte *dest;
byte *prev;
byte *destStart, *destEnd;
byte *prevStart, *prevEnd;
uint32_t pitch;
int coordMap[64];
int coordScaledMap1[64];
int coordScaledMap2[64];
int coordScaledMap3[64];
int coordScaledMap4[64];
};
/** IDs for different data types used in Bink video codec. */
enum Source {
kSourceBlockTypes = 0, ///< 8x8 block types.
kSourceSubBlockTypes , ///< 16x16 block types (a subset of 8x8 block types).
kSourceColors , ///< Pixel values used for different block types.
kSourcePattern , ///< 8-bit values for 2-color pattern fill.
kSourceXOff , ///< X components of motion value.
kSourceYOff , ///< Y components of motion value.
kSourceIntraDC , ///< DC values for intrablocks with DCT.
kSourceInterDC , ///< DC values for interblocks with DCT.
kSourceRun , ///< Run lengths for special fill block.
kSourceMAX
};
/** Bink video block types. */
enum BlockType {
kBlockSkip = 0, ///< Skipped block.
kBlockScaled , ///< Block has size 16x16.
kBlockMotion , ///< Block is copied from previous frame with some offset.
kBlockRun , ///< Block is composed from runs of colors with custom scan order.
kBlockResidue , ///< Motion block with some difference added.
kBlockIntra , ///< Intra DCT block.
kBlockFill , ///< Block is filled with single color.
kBlockInter , ///< Motion block with DCT applied to the difference.
kBlockPattern , ///< Block is filled with two colors following custom pattern.
kBlockRaw ///< Uncoded 8x8 block.
};
/** Data structure for decoding and translating Huffman'd data. */
struct Huffman {
int index; ///< Index of the Huffman codebook to use.
byte symbols[16]; ///< Huffman symbol => Bink symbol translation list.
Huffman();
};
/** Data structure used for decoding a single Bink data type. */
struct Bundle {
int countLengths[2]; ///< Lengths of number of entries to decode (in bits).
int countLength; ///< Length of number of entries to decode (in bits) for the current plane.
Huffman huffman; ///< Huffman codebook.
std::unique_ptr<byte[]> data; ///< Buffer for decoded symbols.
byte *dataEnd; ///< Pointer to the data end end.
byte *curDec; ///< Pointer to the data that wasn't yet decoded.
byte *curPtr; ///< Pointer to the data that wasn't yet read.
Bundle();
};
uint32_t _width;
uint32_t _height;
int _curFrame; ///< Current Frame.
int _frameCount;
Common::Rational _frameRate; ///< The frame rate of the video.
bool _swapPlanes; ///< Are the planes ordered (A)YVU instead of (A)YUV?
bool _hasAlpha; ///< Do video frames have alpha?
uint32_t _id; ///< The BIK FourCC.
Bundle _bundles[kSourceMAX]; ///< Bundles for decoding all data types.
std::unique_ptr<Common::Huffman> _huffman[16]; ///< The 16 Huffman codebooks used in Bink decoding.
/** Huffman codebooks to use for decoding high nibbles in color data types. */
Huffman _colHighHuffman[16];
/** Value of the last decoded high nibble in color data types. */
int _colLastVal;
std::unique_ptr<byte[]> _curPlanes[4]; ///< The 4 color planes, YUVA, current frame.
std::unique_ptr<byte[]> _oldPlanes[4]; ///< The 4 color planes, YUVA, last frame.
/** Initialize the bundles. */
void initBundles();
/** Initialize the Huffman decoders. */
void initHuffman();
/** Decode a video packet. */
void videoPacket(VideoFrame &video);
/** Decode a plane. */
void decodePlane(VideoFrame &video, int planeIdx, bool isChroma);
/** Read/Initialize a bundle for decoding a plane. */
void readBundle(VideoFrame &video, Source source);
/** Read the symbols for a Huffman code. */
void readHuffman(VideoFrame &video, Huffman &huffman);
/** Merge two Huffman symbol lists. */
void mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size);
/** Read and translate a symbol out of a Huffman code. */
byte getHuffmanSymbol(VideoFrame &video, Huffman &huffman);
/** Get a direct value out of a bundle. */
int32_t getBundleValue(Source source);
/** Read a count value out of a bundle. */
uint32_t readBundleCount(VideoFrame &video, Bundle &bundle);
// Handle the block types
void blockSkip (DecodeContext &ctx);
void blockScaledSkip (DecodeContext &ctx);
void blockScaledRun (DecodeContext &ctx);
void blockScaledIntra (DecodeContext &ctx);
void blockScaledFill (DecodeContext &ctx);
void blockScaledPattern(DecodeContext &ctx);
void blockScaledRaw (DecodeContext &ctx);
void blockScaled (DecodeContext &ctx);
void blockMotion (DecodeContext &ctx);
void blockRun (DecodeContext &ctx);
void blockResidue (DecodeContext &ctx);
void blockIntra (DecodeContext &ctx);
void blockFill (DecodeContext &ctx);
void blockInter (DecodeContext &ctx);
void blockPattern (DecodeContext &ctx);
void blockRaw (DecodeContext &ctx);
// Read the bundles
void readRuns (VideoFrame &video, Bundle &bundle);
void readMotionValues(VideoFrame &video, Bundle &bundle);
void readBlockTypes (VideoFrame &video, Bundle &bundle);
void readPatterns (VideoFrame &video, Bundle &bundle);
void readColors (VideoFrame &video, Bundle &bundle);
void readDCS (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign);
void readDCTCoeffs (VideoFrame &video, int16_t *block, bool isIntra);
void readResidue (VideoFrame &video, int16_t *block, int masksCount);
// Bink video IDCT
void IDCT(int16_t *block);
void IDCTPut(DecodeContext &ctx, int16_t *block);
void IDCTAdd(DecodeContext &ctx, int16_t *block);
};
class BinkAudioTrack : public AudioTrack {
public:
BinkAudioTrack(size_t index, AudioInfo &audio);
~BinkAudioTrack();
bool canBufferData() const;
/** Decode audio data up to endTime. */
void decodeAudio(Common::SeekableReadStream& bink, const std::vector<VideoFrame>& frames, const std::vector<AudioInfo>& audioTracks, const Common::Timestamp& endTime);
protected:
Sound::AudioStream *getAudioStream() const;
private:
size_t _index;
AudioInfo &_info;
Sound::PacketizedAudioStream *_audioStream;
uint32_t _curFrame;
Common::Timestamp _audioBuffered;
float getFloat(Common::BitStream &bits);
/** Decode an audio block. */
void audioBlock(Common::BitStream &bits, int16_t *out);
/** Decode a DCT'd audio block. */
void audioBlockDCT(Common::BitStream &bits);
/** Decode a RDFT'd audio block. */
void audioBlockRDFT(Common::BitStream &bits);
void readAudioCoeffs(Common::BitStream &bits, float *coeffs);
static void floatToInt16Interleave(int16_t *dst, const float **src, uint32_t length, uint8_t channels);
};
void initAudioTrack(AudioInfo &audio);
};
} // End of namespace Video
#endif // VIDEO_BINK_H

105
enums.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef ENUMS_H
#define ENUMS_H
#include "qtypes.h"
enum LUMP_TYPE
{
LUMP_MATERIALS = 0x0,
LUMP_LIGHTBYTES = 0x1,
LUMP_LIGHTGRIDENTRIES = 0x2,
LUMP_LIGHTGRIDCOLORS = 0x3,
LUMP_PLANES = 0x4,
LUMP_BRUSHSIDES = 0x5,
LUMP_BRUSHSIDEEDGECOUNTS = 0x6,
LUMP_BRUSHEDGES = 0x7,
LUMP_BRUSHES = 0x8,
LUMP_TRIANGLES = 0x9,
LUMP_DRAWVERTS = 0xA,
LUMP_DRAWINDICES = 0xB,
LUMP_CULLGROUPS = 0xC,
LUMP_CULLGROUPINDICES = 0xD,
LUMP_OBSOLETE_1 = 0xE,
LUMP_OBSOLETE_2 = 0xF,
LUMP_OBSOLETE_3 = 0x10,
LUMP_OBSOLETE_4 = 0x11,
LUMP_OBSOLETE_5 = 0x12,
LUMP_PORTALVERTS = 0x13,
LUMP_OBSOLETE_6 = 0x14,
LUMP_UINDS = 0x15,
LUMP_BRUSHVERTSCOUNTS = 0x16,
LUMP_BRUSHVERTS = 0x17,
LUMP_AABBTREES = 0x18,
LUMP_CELLS = 0x19,
LUMP_PORTALS = 0x1A,
LUMP_NODES = 0x1B,
LUMP_LEAFS = 0x1C,
LUMP_LEAFBRUSHES = 0x1D,
LUMP_LEAFSURFACES = 0x1E,
LUMP_COLLISIONVERTS = 0x1F,
LUMP_COLLISIONTRIS = 0x20,
LUMP_COLLISIONEDGEWALKABLE = 0x21,
LUMP_COLLISIONBORDERS = 0x22,
LUMP_COLLISIONPARTITIONS = 0x23,
LUMP_COLLISIONAABBS = 0x24,
LUMP_MODELS = 0x25,
LUMP_VISIBILITY = 0x26,
LUMP_ENTITIES = 0x27,
LUMP_PATHCONNECTIONS = 0x28,
LUMP_REFLECTION_PROBES = 0x29,
LUMP_VERTEX_LAYER_DATA = 0x2A,
LUMP_PRIMARY_LIGHTS = 0x2B,
LUMP_LIGHTGRIDHEADER = 0x2C,
LUMP_LIGHTGRIDROWS = 0x2D,
LUMP_OBSOLETE_10 = 0x2E,
//Obsolete in BO1/////////////////
LUMP_UNLAYERED_TRIANGLES = 0x2F,
LUMP_UNLAYERED_DRAWVERTS = 0x30,
LUMP_UNLAYERED_DRAWINDICES = 0x31,
LUMP_UNLAYERED_CULLGROUPS = 0x32,
LUMP_UNLAYERED_AABBTREES = 0x33,
//////////////////////////////////
LUMP_WATERHEADER = 0x34,
LUMP_WATERCELLS = 0x35,
LUMP_WATERCELLDATA = 0x36,
LUMP_BURNABLEHEADER = 0x37,
LUMP_BURNABLECELLS = 0x38,
LUMP_BURNABLECELLDATA = 0x39,
LUMP_SIMPLELIGHTMAPBYTES = 0x3A,
LUMP_LODCHAINS = 0x3B,
LUMP_LODINFOS = 0x3C,
LUMP_LODSURFACES = 0x3D,
LUMP_LIGHTREGIONS = 0x3E,
LUMP_LIGHTREGION_HULLS = 0x3F,
LUMP_LIGHTREGION_AXES = 0x40,
LUMP_WIILIGHTGRID = 0x41,
LUMP_LIGHTGRID2D_LIGHTS = 0x42,
LUMP_LIGHTGRID2D_INDICES = 0x43,
LUMP_LIGHTGRID2D_POINTS = 0x44,
LUMP_LIGHTGRID2D_CELLS = 0x45,
LUMP_LIGHT_CORONAS = 0x46,
//BO Specific/////////////////////////
LUMP_SHADOWMAP_VOLUMES = 0x47,
LUMP_SHADOWMAP_VOLUME_PLANES = 0x48,
LUMP_EXPOSURE_VOLUMES = 0x49,
LUMP_EXPOSURE_VOLUME_PLANES = 0x4A,
LUMP_OCCLUDERS = 0x4B,
LUMP_OUTDOORBOUNDS = 0x4C,
LUMP_HERO_ONLY_LIGHTS = 0x4D,
//////////////////////////////////////
INFO_LUMP_TYPE_COUNT
};
enum BSPVERSION_TYPE
{
BSPVERSION_COD_WAW = 31,
BSPVERSION_COD_BO = 45
};
// Bink constants
const quint32 BINK_SURFACE32RGBA = 6;
#endif // ENUMS_H

View File

@ -314,12 +314,26 @@ RawFile ZoneFile_COD5::pParseAsset_RawFile(QDataStream *aZoneFileStream) {
*aZoneFileStream >> scriptPathChar; *aZoneFileStream >> scriptPathChar;
} }
result.path.replace(",", ""); result.path.replace(",", "");
const QStringList pathParts = result.path.split('/'); const QStringList pathParts = result.path.split('/');
if (pathParts.size() == 0) { if (pathParts.size() == 0) {
qDebug() << "Failed to parse ff path! " << result.path; qDebug() << "Failed to parse ff path! " << result.path;
exit(-1); exit(-1);
} }
if (result.path.contains(".bik")) {
qDebug() << "rawFileLength: " << result.length;
QByteArray bikData(result.length, Qt::Uninitialized);
aZoneFileStream->readRawData(bikData.data(), result.length);
//QFile bikFile(QDir::currentPath() + "/" + rawFilePath.split('/').last());
//qDebug() << bikFile.fileName();
//if (!bikFile.open(QIODevice::WriteOnly)) {
// qWarning() << "Failed to open .bik file for writing!";
// return;
//}
//qDebug() << QString("%1: %2").arg(rawFilePath).arg(bikFile.fileName());
//bikFile.write(bikData);
} else {
// Parse gsc contents // Parse gsc contents
char rawFileContentsChar; char rawFileContentsChar;
*aZoneFileStream >> rawFileContentsChar; *aZoneFileStream >> rawFileContentsChar;
@ -327,6 +341,7 @@ RawFile ZoneFile_COD5::pParseAsset_RawFile(QDataStream *aZoneFileStream) {
result.contents += rawFileContentsChar; result.contents += rawFileContentsChar;
*aZoneFileStream >> rawFileContentsChar; *aZoneFileStream >> rawFileContentsChar;
} }
}
return result; return result;
} }
@ -396,8 +411,64 @@ Model ZoneFile_COD5::pParseAsset_Model(QDataStream *aZoneFileStream) {
} }
Material ZoneFile_COD5::pParseAsset_Material(QDataStream *aZoneFileStream) { Material ZoneFile_COD5::pParseAsset_Material(QDataStream *aZoneFileStream) {
Q_UNUSED(aZoneFileStream); aZoneFileStream->skipRawData(27 * 4);
qint32 materialNamePtr;
*aZoneFileStream >> materialNamePtr;
qDebug() << "materialNamePtr: " << materialNamePtr;
if (materialNamePtr == -1) {
QString materialName;
char materialNameChar;
*aZoneFileStream >> materialNameChar;
while (materialNameChar != 0) {
materialName += materialNameChar;
*aZoneFileStream >> materialNameChar;
}
qDebug() << "Parsing Material: " << materialName;
}
aZoneFileStream->skipRawData(3 * 4);
qint32 compressionPtr, compression, unknownSectionPtr;
*aZoneFileStream >> compressionPtr;
qDebug() << "compressionPtr: " << compressionPtr;
if (compressionPtr == -1) {
*aZoneFileStream >> compression;
qDebug() << QString("Found material with DXT%1 compression!").arg(compression);
*aZoneFileStream >> unknownSectionPtr;
qDebug() << "unknownSectionPtr: " << unknownSectionPtr;
if (unknownSectionPtr == -2) {
aZoneFileStream->skipRawData(6 * 4);
}
}
qint32 imageNamePtr;
*aZoneFileStream >> imageNamePtr;
qDebug() << "imageNamePtr: " << imageNamePtr;
if (imageNamePtr == -1) {
QString imageName;
char imageNameChar;
*aZoneFileStream >> imageNameChar;
while (imageNameChar != 0) {
imageName += imageNameChar;
*aZoneFileStream >> imageNameChar;
}
qDebug() << "- Embeded image: " << imageName;
}
QByteArray compressionData(4, Qt::Uninitialized);
QString compressionStr;
if (compressionPtr == -1) {
aZoneFileStream->skipRawData(2 * 4);
aZoneFileStream->readRawData(compressionData.data(), 4);
aZoneFileStream->skipRawData(4);
compressionStr = QString::fromUtf8(compressionData);
aZoneFileStream->skipRawData(4);
}
aZoneFileStream->skipRawData(4);
// TODO: Fill out this material
return Material(); return Material();
} }