/*************************************************************************** * Copyright (C) 2010 * by thakis * * Modification and adjustment for the Wii by Dimok * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any * purpose, including commercial applications, and to alter it and * redistribute it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you * must not claim that you wrote the original software. If you use * this software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and * must not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. * * gcvid.h ***************************************************************************/ #ifndef THAKIS_GCVID_H #define THAKIS_GCVID_H THAKIS_GCVID_H #include //FILE* #include #include using std::string; using std::vector; #include #pragma pack(push, 1) ///////////////////////////////////////////////////////////////////// //THP struct ThpHeader { char tag[4]; //'THP\0' //from monk's thp player: u32 version; //0x00011000 = 1.1, 0x00010000 = 1.0 u32 maxBufferSize; u32 maxAudioSamples; //!= 0 if sound is stored in file float fps; //usually 29.something (=0x41efc28f) for ntsc u32 numFrames; u32 firstFrameSize; //size of first frame u32 dataSize; //size of file - ThpHeader.offset //from monk's thp player: u32 componentDataOffset; //ThpComponents stored here u32 offsetsDataOffset; //?? if != 0, offset to table with offsets of all frames? u32 firstFrameOffset; u32 lastFrameOffset; }; //monk: struct ThpComponents { u32 numComponents; //usually 1 or 2 (video or video + audio) //component type 0 is video, type 1 is audio, //type 0xff is "no component" (numComponent many entries //are != 0xff) u8 componentTypes[16]; }; struct ThpVideoInfo { u32 width; u32 height; u32 unknown; //only for version 1.1 thp files }; struct ThpAudioInfo { u32 numChannels; u32 frequency; u32 numSamples; u32 numData; //only for version 1.1 - that many //audio blocks are after each video block //(for surround sound?) }; //endmonk //a frame image is basically a normal jpeg image (without //the jfif application marker), the only important difference //is that after the image start marker (0xff 0xda) values //of 0xff are simply written as 0xff whereas the jpeg //standard requires them to be written as 0xff 0x00 because //0xff is the start of a 2-byte control code in jpeg //frame (offsets relative to frame start): //u32 total (image, sound, etc) size of NEXT frame //u32 size1 at 0x04 (total size of PREV frame according to monk) //u32 image data size at 0x08 //size of one audio block ONLY IF THE FILE HAS SOUND. ThpAudioInfo.numData //many audio blocks after jpeg data //jpeg data //audio block(s) struct ThpAudioBlockHeader { //size 80 byte u32 channelSize; //size of one channel in bytes u32 numSamples; //number of samples/channel s16 table1[16]; //table for first channel s16 table2[16]; //table for second channel s16 channel1Prev1; s16 channel1Prev2; s16 channel2Prev1; s16 channel2Prev2; }; //audio block: //u32 size of this audioblock // //u32 numBytes/channel of audioblock - that many bytes per channel after adpcm table) // //u32 number of samples per channel // //2*16 shorts adpcm table (one per channel - always stored both, //even for mono files), 5.11 fixed point values // //4 s16: 2 shorts prev1 and prev2 for each channel (even for mono files) // //sound data //sound data: //8 byte are 14 samples: //the first byte stores index (upper nibble) and shift (lower nibble), //the following 7 bytes contain 14o samples a 4 bit each ///////////////////////////////////////////////////////////////////// //MTH ("mute thp"?) //similar to a thp file, but without sound struct MthHeader { //one of the unknown has to be fps in some form char tag[4]; //'MTHP' u32 unknown; u32 unknown2; u32 maxFrameSize; u32 width; u32 height; u32 fps; u32 numFrames; u32 offset; u32 unknown5; u32 firstFrameSize; //5 padding u32's follow }; //frame: //u32 size of NEXT frame //jpeg data //see thp (above) for jpeg format. there's a small difference, though: //mth jpegs end with 0xff 0xd9 0xff instead of 0xff 0xd9 #pragma pack(pop) //little helper class that represents one frame of video //data is 24 bpp, scanlines aligned to 4 byte boundary class VideoFrame { public: VideoFrame() : data(NULL), _w(0), _h(0), _p(0) { }; ~VideoFrame() { }; u8 *data; //texdata style void resize(int width, int height); int getWidth() const; int getHeight() const; int getPitch() const; void dealloc(); private: int _w; int _h; int _p; //pitch in bytes //copy constructor and asignment operator are not allowed //VideoFrame(const VideoFrame& f); VideoFrame& operator=(const VideoFrame& f); }; class VideoFile { public: VideoFile(FILE* f); virtual ~VideoFile(); virtual int getWidth() const; virtual int getHeight() const; virtual float getFps() const; virtual int getFrameCount() const; virtual int getCurrentFrameNr() const; virtual bool loadNextFrame(bool skip = false) = 0; virtual void getCurrentFrame(VideoFrame& frame) = 0; //sound support: virtual bool hasSound() const; virtual int getNumChannels() const; virtual int getFrequency() const; virtual int getMaxAudioSamples() const; virtual int getCurrentBuffer(s16* data) const; bool loop; protected: FILE* _f; //void loadFrame(long offset, int size); virtual void loadFrame(VideoFrame& frame, const u8* src, int src_size); int countRequiredSize(const u8* src, int src_size, int& start, int& end); void convertToRealJpeg(u8* dest, const u8* src, int srcSize, int start, int end); }; VideoFile* openVideo(const std::string& fileName); void closeVideo(VideoFile*& vf); class ThpVideoFile : public VideoFile { public: ThpVideoFile() : VideoFile(NULL) { }; ThpVideoFile(FILE* f) : VideoFile(f) { Init(f); }; bool Init(FILE *f); void DeInit(); virtual int getWidth() const; virtual int getHeight() const; virtual float getFps() const; virtual int getFrameCount() const; virtual int getCurrentFrameNr() const; virtual bool loadNextFrame(bool skip = false); virtual void getCurrentFrame(VideoFrame& frame); virtual bool hasSound() const; virtual int getNumChannels() const; virtual int getFrequency() const; virtual int getMaxAudioSamples() const; virtual int getCurrentBuffer(s16* data) const; virtual void loadFrame(VideoFrame& frame, const u8* src, int src_size); protected: ThpHeader _head; ThpComponents _components; ThpVideoInfo _videoInfo; ThpAudioInfo _audioInfo; int _numInts; int _currFrameNr; int _nextFrameOffset; int _nextFrameSize; u8 *_currFrameData; u8 *_currFrameRealData; }; class MthVideoFile : public VideoFile { public: MthVideoFile(FILE* f); virtual int getWidth() const; virtual int getHeight() const; virtual float getFps() const; virtual int getFrameCount() const; virtual int getCurrentFrameNr() const; virtual bool loadNextFrame(bool skip = false); virtual void getCurrentFrame(VideoFrame& frame); protected: MthHeader _head; int _currFrameNr; int _nextFrameOffset; int _nextFrameSize; int _thisFrameSize; vector _currFrameData; }; class JpgVideoFile : public VideoFile { public: JpgVideoFile(FILE* f); virtual int getWidth() const; virtual int getHeight() const; virtual int getFrameCount() const; virtual bool loadNextFrame(bool skip = false) { return skip; } virtual void getCurrentFrame(VideoFrame& frame); private: VideoFrame _currFrame; }; void decodeRealJpeg(const u8* data, int size, VideoFrame& dest, bool fancy = false); #endif //THAKIS_GCVID_H