/*---------------------------------------------------------------------------* Project: Revolution THP Utilities Library File: thputilities.c Copyright (C)2002-2006 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: thputilities.c,v $ Revision 1.1 2006/02/08 02:57:09 aka Imported from Dolphin Tree. 15 2003/12/24 3:00p Akagi Revised a comment. 14 2003/12/24 1:58p Akagi Added THPUtyCopyTHPFile(). 13 2003/12/10 10:17a Akagi Revised THP version in THPUtyReadTHPFileHeader(). 12 2003/09/21 6:44p Akagi Added THP file check during reading THPHeader. 11 2003/09/15 5:56p Akagi Renamed all functions from THPCONVXXXX to THPUtyXXXX. Added some comments. 10 2003/07/03 11:04a Akagi Renamed some functions. 9 2003/07/01 2:34p Akagi Modified to divide old THPConv.exe into 2 LIBs and 1 EXE by Ohki-san@NTSC. 8 2003/07/01 2:26p Akagi Moved from build/tools/THPConv/src. 7 2003/07/01 9:54a Akagi Moved from securebuild/tools. 6 2002/10/16 11:28a Akagi JPEG & WAV file Name bug fixed. (by iRD tsuji) 5 2002/05/08 2:31p Akagi Modified [-trk] option By Tsuji (IRD) 1 2002/01/16 4:59p Akagi Initial revision made by Tsuji-san (IRD). $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- // Local Functions //----------------------------------------------------------------------------- static s32 THPUtyWriteVideoOneFrame( FILE* thpFp, THPFileName* fileName, THPImageStatus* imageStatus ); static s32 THPUtyWriteAudioOneFrame( FILE* thpFp, THPFileHeader* fileHeader, THPAudioHandle** audioHandleList, u32 frameSize, u32 frameNum ); static s32 THPUtyCopyVideoFrame ( FILE* thpFp, FILE* videoTHPFp, THPFileHeader* videoFileHeader, u32* videoCompSize ); /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------* * Utility Functions * *---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: THPUtyConvertToUnixFmt Description: Converts the Unix-format path specified in fmt to DOS format. Be aware that the buffer specified by fmt is overwritten. Arguments: fmt: a pointer to the string to be converted Returns: None. *---------------------------------------------------------------------------*/ void THPUtyConvertToUnixFmt(char* fmt) { char* fmt_start = fmt; char temp[256]; char* temp_ptr = temp; strcpy(temp_ptr, fmt); if (temp_ptr == NULL) { return; } while (*temp_ptr != '\0') { if ((*temp_ptr == '/') && (*(temp_ptr + 1) == '/')) { *fmt = *(temp_ptr + 2); *(fmt + 1) = ':'; *(fmt + 2) = '\\'; fmt += 3; temp_ptr += 3; } else if ((*temp_ptr == '.') && (*(temp_ptr + 1) == '.') && (*(temp_ptr + 2) == '/')) { *fmt = '.'; *(fmt + 1) = '.'; *(fmt + 2) = '\\'; fmt += 3; temp_ptr += 3; } else if (*temp_ptr == '/') { *(fmt) = '\\'; fmt++; temp_ptr++; } else { *fmt = *temp_ptr; fmt++; temp_ptr++; } } } /*---------------------------------------------------------------------------* Name: THPUtyReverseEndianU16 Description: Converts a 16-bit value endian. Arguments: data: a 16-bit value endian to be converted Returns: an endian-converted value *---------------------------------------------------------------------------*/ u16 THPUtyReverseEndianU16(u16 data) { #if 1 __asm { mov ax, data; rol ax, 8; mov data, ax; } return data; #else return (u16)(((data & 0x00FF) << 8) | ((data & 0xFF00) >> 8)); #endif } /*---------------------------------------------------------------------------* Name: THPUtyReverseEndianU32 Description: Converts a 32-bit value endian. Arguments: data: a 32-bit value endian to be converted Returns: an endian-converted value *---------------------------------------------------------------------------*/ u32 THPUtyReverseEndianU32(u32 data) { #if 1 __asm { mov eax, data; bswap eax; mov data, eax; } return data; #else return(((data >> 24) & 0x000000ff) | ((data >> 8) & 0x0000ff00) | ((data << 8) & 0x00ff0000) | ((data << 24) & 0xff000000) ); #endif } /*---------------------------------------------------------------------------* Name: THPUtyReverseEndianF32 Description: Converts a 32-bit floating value endian. Arguments: data: a floating value endian to be converted Returns: an endian-converted floating value *---------------------------------------------------------------------------*/ f32 THPUtyReverseEndianF32(f32 data) { u8* src = (u8 *)&data; f32 result; u8* r = (u8*)&result; r[3] = src[0]; r[2] = src[1]; r[1] = src[2]; r[0] = src[3]; return(result); } /*---------------------------------------------------------------------------* Name: THPUtyWritePad32 Description: Outputs NULLs to the file to make it 32-byte aligned. Arguments: op: a pointer to the output file bytes: the size of the data just output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWritePad32(FILE* op, u32 bytes) { u32 remainder = 32 - (bytes & ((u32)31)); u8 val = 0; u8 buffer[32]; size_t ret; // no real remainder if (remainder == 32) { return THP_ERROR_NOERROR; } THPPrintLog("Adding %ld pad bytes\n", remainder); memset(buffer, 0, sizeof(buffer)); ret = fwrite(buffer, remainder, 1, op); if (ret != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyPutU32 Description: Converts the endian for u32-type data and outputs to a file specified by op. Arguments: op: a pointer to the output file data: the u32-type value to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyPutU32(FILE *op, u32 data) { s32 rtn; u8 buffer[4]; buffer[0] = (u8)(data >> 24); buffer[1] = (u8)(data >> 16); buffer[2] = (u8)(data >> 8); buffer[3] = (u8)(data >> 0); rtn = fwrite(buffer, 4, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyPutF32 Description: Converts the endian for f32-type data and outputs to a file specified by op. Arguments: op: a pointer to the output file data: the f32-type value to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyPutF32(FILE *op, f32 data) { u32 data_u32; memcpy(&data_u32, &data, 4); return THPUtyPutU32(op, data_u32); } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------* * THP File Write Functions * *---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: THPUtyHeaderInit Description: Initializes the THPHeader structure. Arguments: header: a pointer to the THPHeader structure Returns: None. *---------------------------------------------------------------------------*/ void THPUtyHeaderInit(THPHeader* header) { header->magic[0] = 'T'; header->magic[1] = 'H'; header->magic[2] = 'P'; header->magic[3] = '\0'; header->version = THP_VERSION; header->bufSize = 0; header->audioMaxSamples = 0; header->frameRate = 0.0F; header->numFrames = 0; // frames total header->firstFrameSize = 0; header->movieDataSize = 0; header->compInfoDataOffsets = 0; header->offsetDataOffsets = 0; header->movieDataOffsets = 0; header->finalFrameDataOffsets = 0; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPHeader Description: Outputs the THPHeader structure to a file specified by op. Arguments: op: a pointer to the output file header: a pointer to the THPHeader structure to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPHeader(FILE *op, THPHeader *header) { s32 rtn; rtn = fwrite(header->magic, 4, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } if ((rtn = THPUtyPutU32(op, header->version)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->bufSize)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->audioMaxSamples)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutF32(op, header->frameRate)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->numFrames)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->firstFrameSize)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->movieDataSize)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->compInfoDataOffsets)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->offsetDataOffsets)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->movieDataOffsets)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, header->finalFrameDataOffsets)) != THP_ERROR_NOERROR) { return rtn; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPFrameCompInfo Description: Outputs the THPFrameCompInfo structure to a file specified by op. Arguments: op: a pointer to the output file compinfo: a pointer to the THPFrameCompInfo structure to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPFrameCompInfo(FILE *op, THPFrameCompInfo *compinfo) { s32 rtn; if ((rtn = THPUtyPutU32(op, compinfo->numComponents)) != THP_ERROR_NOERROR) { return rtn; } rtn = fwrite(compinfo->frameComp, THP_COMP_MAX, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPVideoInfo Description: Outputs the THPVideoInfo structure to a file specified by op. Arguments: op: a pointer to the output file videoinfo: a pointer to the THPVideoInfo structure to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPVideoInfo(FILE *op, THPVideoInfo *videoinfo) { s32 rtn; if ((rtn = THPUtyPutU32(op, videoinfo->xSize)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, videoinfo->ySize)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, videoinfo->videoType)) != THP_ERROR_NOERROR) { return rtn; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPAudioInfo Description: Outputs the THPAudioInfo structure to a file specified by op. Arguments: op: a pointer to the output file audioinfo: a pointer to the THPAudioInfo structure to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPAudioInfo(FILE *op, THPAudioInfo *audioinfo) { s32 rtn; if ((rtn = THPUtyPutU32(op, audioinfo->sndChannels)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, audioinfo->sndFrequency)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, audioinfo->sndNumSamples)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, audioinfo->sndNumTracks)) != THP_ERROR_NOERROR) { return rtn; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPFrameHeader Description: Outputs the THPFrameHeader structure to a file specified by op. Arguments: op: a pointer to the output file frameCompInfo: a pointer to the THPFrameCompInfo structure frameHeader: a pointer to the THPFrameHeader structure to be output Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPFrameHeader(FILE* op, THPFrameCompInfo* frameCompInfo, THPFrameHeader* frameHeader) { u32 i; s32 rtn; if ((rtn = THPUtyPutU32(op, frameHeader->frameSizeNext)) != THP_ERROR_NOERROR) { return rtn; } if ((rtn = THPUtyPutU32(op, frameHeader->frameSizePrevious)) != THP_ERROR_NOERROR) { return rtn; } for (i = 0; i < frameCompInfo->numComponents; i++) { if ((rtn = THPUtyPutU32(op, frameHeader->comp[i])) != THP_ERROR_NOERROR) { return rtn; } } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPComponentsInfo Description: Outputs the THPVideoInfo and THPAudioInfo structures to a file specified by op. Arguments: op: a pointer to the output file compinfo: a pointer to the THPFrameCompInfo structure videoinfo: a pointer to the THPVideoInfo structure to be output audioinfo: a pointer to the THPAudioInfo structure to be output compinfosize: a pointer to the storage of the component size Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed THP_ERROR_DATA: data error *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPComponentsInfo(FILE* op, THPFrameCompInfo* compinfo, THPVideoInfo* videoinfo, THPAudioInfo* audioinfo, s32* compinfosize) { u32 i; s32 size = 0; s32 rtn; for (i = 0; i < compinfo->numComponents; i++) { switch (compinfo->frameComp[i]) { case THP_VIDEO_COMP: rtn = THPUtyWriteTHPVideoInfo(op, videoinfo); if (rtn != THP_ERROR_NOERROR) { return rtn; } size += sizeof(THPVideoInfo); break; case THP_AUDIO_COMP: rtn = THPUtyWriteTHPAudioInfo(op, audioinfo); if (rtn != THP_ERROR_NOERROR) { return rtn; } size += sizeof(THPAudioInfo); break; case THP_NOCOMP_COMP: THPPrintError("\aERROR : Strange numComponents (%ld)\n", __LINE__); return THP_ERROR_DATA; break; default: THPPrintError("\aERROR : Unsupported Components (%ld)\n", __LINE__); return THP_ERROR_DATA; break; } } if (compinfosize != NULL) { *compinfosize = size; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyWriteTHPFileHeader Description: Outputs the THPFileHeader structure to a file specified by op. Arguments: op: a pointer to the output file fileHeader: a pointer to the THPFileHeader structure to be output compInfoSize: a pointer to the storage of the component size Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed THP_ERROR_DATA: data error *---------------------------------------------------------------------------*/ s32 THPUtyWriteTHPFileHeader(FILE* op, THPFileHeader* fileHeader, s32* compInfoSize) { s32 rtn; rtn = fseek(op, 0, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Write THPHeader, THPFrameCompInfo, THPVideoInfo, THPAudioInfo(Update after Convert) rtn = THPUtyWriteTHPHeader(op, &fileHeader->header); if (rtn != THP_ERROR_NOERROR) { return rtn;; } rtn = fseek(op, fileHeader->header.compInfoDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } rtn = THPUtyWriteTHPFrameCompInfo(op, &fileHeader->frameCompInfo); if (rtn != THP_ERROR_NOERROR) { return rtn; } rtn = THPUtyWriteTHPComponentsInfo(op, &fileHeader->frameCompInfo, &fileHeader->videoInfo, &fileHeader->audioInfo, compInfoSize); if (rtn != THP_ERROR_NOERROR) { return rtn; } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------* * THP File Read Functions * *---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: THPUtyReadTHPHeader Description: Reads the THPHeader structure from a THP file specified by ip. The read position needs to be set to the THPHeader position in advance. Arguments: ip: a file pointer to the THP file header: a pointer to the THPHeader structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error THP_ERROR_THPFILE: THP file error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPHeader(FILE *ip, THPHeader *header) { s32 rtn; rtn = fread(header, sizeof(THPHeader), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // magic check if (memcmp(header->magic, "THP\0", 4)) { THPPrintError("\aERROR : this will not be a THP file (%ld)\n", __LINE__); return THP_ERROR_THPFILE; } // Reverse Endian header->version = THPUtyReverseEndianU32(header->version); header->bufSize = THPUtyReverseEndianU32(header->bufSize); header->audioMaxSamples = THPUtyReverseEndianU32(header->audioMaxSamples); header->frameRate = THPUtyReverseEndianF32(header->frameRate); header->numFrames = THPUtyReverseEndianU32(header->numFrames); header->firstFrameSize = THPUtyReverseEndianU32(header->firstFrameSize); header->movieDataSize = THPUtyReverseEndianU32(header->movieDataSize); header->compInfoDataOffsets = THPUtyReverseEndianU32(header->compInfoDataOffsets); header->offsetDataOffsets = THPUtyReverseEndianU32(header->offsetDataOffsets); header->movieDataOffsets = THPUtyReverseEndianU32(header->movieDataOffsets); header->finalFrameDataOffsets = THPUtyReverseEndianU32(header->finalFrameDataOffsets); return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPFrameCompInfo Description: Reads the THPFrameCompInfo structure from a THP file specified by ip. The read position needs to be set to the THPFrameCompInfo position in advance. Arguments: ip: a file pointer to the THP file compinfo: a pointer to the THPFrameCompInfo structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPFrameCompInfo(FILE *ip, THPFrameCompInfo *compinfo) { s32 rtn; rtn = fread(compinfo, sizeof(THPFrameCompInfo), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian compinfo->numComponents = THPUtyReverseEndianU32(compinfo->numComponents); return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPVideoInfo Description: Reads the THPVideoInfo structure from a THP file specified by ip. The read position needs to be set to the THPVideoInfo position in advance. Arguments: ip: a file pointer to the THP file videoinfo: a pointer to the THPVideoInfo structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPVideoInfo(FILE *ip, THPVideoInfo *videoinfo) { s32 rtn; rtn = fread(videoinfo, sizeof(THPVideoInfo), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian videoinfo->xSize = THPUtyReverseEndianU32(videoinfo->xSize); videoinfo->ySize = THPUtyReverseEndianU32(videoinfo->ySize); videoinfo->videoType = THPUtyReverseEndianU32(videoinfo->videoType); return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPVideoInfoOld Description: Reads the THPVideoInfo structure from a version 1.0 or older THP file specified by ip. The read position needs to be set to the THPVideoInfo position in advance. Arguments: ip: a file pointer to a version 1.0 or older THP file videoinfo: a pointer to the THPVideoInfo structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPVideoInfoOld(FILE *ip, THPVideoInfo *videoinfo) { s32 rtn; THPVideoInfoOld videoinfoOld; rtn = fread(&videoinfoOld, sizeof(THPVideoInfoOld), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian videoinfo->xSize = THPUtyReverseEndianU32(videoinfoOld.xSize); videoinfo->ySize = THPUtyReverseEndianU32(videoinfoOld.ySize); videoinfo->videoType = THP_VIDEO_NON_INTERLACE; return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPAudioInfo Description: Reads the THPAudioInfo structure from a THP file specified by ip. The read position needs to be set to the THPAudioInfo position in advance. Arguments: ip: a file pointer to the THP file audioinfo: a pointer to the THPAudioInfo structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPAudioInfo(FILE *ip, THPAudioInfo *audioinfo) { s32 rtn; rtn = fread(audioinfo, sizeof(THPAudioInfo), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian audioinfo->sndChannels = THPUtyReverseEndianU32(audioinfo->sndChannels); audioinfo->sndFrequency = THPUtyReverseEndianU32(audioinfo->sndFrequency); audioinfo->sndNumSamples = THPUtyReverseEndianU32(audioinfo->sndNumSamples); audioinfo->sndNumTracks = THPUtyReverseEndianU32(audioinfo->sndNumTracks); return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPAudioInfoOld Description: Reads the THPAudioInfo structure from a version 1.0 or older THP file specified by ip. The read position needs to be set to the THPAudioInfo position in advance. Arguments: ip: a file pointer to a version 1.0 or older THP file audioinfo: a pointer to the THPAudioInfo structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPAudioInfoOld(FILE *ip, THPAudioInfo *audioinfo) { s32 rtn; THPAudioInfoOld audioinfoOld; rtn = fread(&audioinfoOld, sizeof(THPAudioInfoOld), 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian audioinfo->sndChannels = THPUtyReverseEndianU32(audioinfoOld.sndChannels); audioinfo->sndFrequency = THPUtyReverseEndianU32(audioinfoOld.sndFrequency); audioinfo->sndNumSamples = THPUtyReverseEndianU32(audioinfoOld.sndNumSamples); audioinfo->sndNumTracks = 1; return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPFrameHeader Description: Reads the THPFrameHeader structure from a THP file specified by ip. The read position needs to be set to the THPFrameHeader position in advance. Arguments: ip: a file pointer to the THP file frameHeader: a pointer to the THPFrameHeader componentNum: the number of components included in the THP file Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPFrameHeader(FILE* ip, THPFrameHeader* frameHeader, s32 componentNum) { s32 rtn; size_t readSize; readSize = componentNum * sizeof(u32) + sizeof(u32) * 2; rtn = fread(frameHeader, readSize, 1,ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Reverse Endian frameHeader->frameSizeNext = THPUtyReverseEndianU32(frameHeader->frameSizeNext); frameHeader->frameSizePrevious = THPUtyReverseEndianU32(frameHeader->frameSizePrevious); { s32 i; for (i = 0; i < componentNum; i++) { frameHeader->comp[i] = THPUtyReverseEndianU32(frameHeader->comp[i]); } } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* Name: THPUtyReadTHPFileHeader Description: Reads the THPFileHeader structure from a THP file specified by ip. The read position needs to be set to the THPFileHeader position in advance. Arguments: ip: a file pointer to the THP file fileHeader: a pointer to the THPFileHeader structure Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read error THP_ERROR_THPFILE: THP file error *---------------------------------------------------------------------------*/ s32 THPUtyReadTHPFileHeader(FILE* ip, THPFileHeader* fileHeader) { s32 rtn; u32 i; // Seek THPHeader Offset rtn = fseek(ip, 0, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Read THPHeader rtn = THPUtyReadTHPHeader(ip, &fileHeader->header); if (rtn != THP_ERROR_NOERROR) { return rtn; } // Seek THPFrameCompInfo Offset rtn = fseek(ip, fileHeader->header.compInfoDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); return THP_ERROR_FILEIO; } // Read THPFrameCompInfo rtn = THPUtyReadTHPFrameCompInfo(ip, &fileHeader->frameCompInfo); if (rtn != THP_ERROR_NOERROR) { return rtn; } // Read THPVideoInfo/THPAudioInfo for (i = 0; i < fileHeader->frameCompInfo.numComponents; i++) { switch (fileHeader->frameCompInfo.frameComp[i]) { case THP_VIDEO_COMP: // THPVideoInfo if (fileHeader->header.version > 0x10000) { // Ver 1.1 or later rtn = THPUtyReadTHPVideoInfo(ip, &fileHeader->videoInfo); } else { // Ver1.0 rtn = THPUtyReadTHPVideoInfoOld(ip, &fileHeader->videoInfo); } if (rtn != THP_ERROR_NOERROR) { return rtn; } break; case THP_AUDIO_COMP: //THPAudioInfo if (fileHeader->header.version > 0x10000) { // Ver 1.1 or later rtn = THPUtyReadTHPAudioInfo(ip, &fileHeader->audioInfo); } else { // Ver1.0 rtn = THPUtyReadTHPAudioInfoOld(ip, &fileHeader->audioInfo); } if (rtn != THP_ERROR_NOERROR) { return rtn; } break; case THP_NOCOMP_COMP: THPPrintError("\aERROR : Strange numComponents (%ld)\n", __LINE__); return THP_ERROR_THPFILE; break; default: THPPrintError("\aERROR : Unsupported Components (%ld)\n", __LINE__); return THP_ERROR_THPFILE; break; } } return THP_ERROR_NOERROR; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------* * THP File Manipulating Functions * *---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: THPUtyCreateTHP Description: Creates a THP file based on the fileHeader information. Arguments: op: a pointer to the output file fileFlag: flag specifying the input data's type filePtr: a pointer to the input data corresponding to fileFlag fileHeader: a pointer to the THPFileHeader structure audioHandleList: a list of pointers to the THPAudioHandle structures Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read/write failure THP_ERROR_JPEGFILE: JPG file error THP_ERROR_THPFILE: THP file error THP_ERROR_DATA: data error THP_ERROR_FATAL: memory allocation failure *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* - fileFlag fileFlag = THP_CREATETHP_FILEFLAG_JPEGS : filePtr is a list of JPG files specified in the THPFileName structure's array. The JPEG files specified by filePtr are converted to THP format and a THP file is created. A list of the specified number in headerHeader.header.numFrames is needed. fileFlag = THP_CREATETHP_FILEFLAG_THP : filePtr is a file pointer to the input THP file. - fileHeader The following members must be set prior to calling. (Other members are set by this function.) [THPHeader] fileHeader->header.magic fileHeader->header.version fileHeader->header.frameRate fileHeader->header.numFrames fileHeader->header.compInfoDataOffsets fileHeader->header.offsetDataOffsets (the value must not be 0 when an offset is used) [THPFrameCompInfo] fileHeader->frameCompInfo.frameComp[] fileHeader->frameCompInfo.numComponents [THPVideoInfo] fileHeader->videoInfo.videoType [THPAudioInfo] fileHeader->audioInfo.sndChannels fileHeader->audioInfo.sndFrequency fileHeader->audioInfo.sndNumSamples fileHeader->audioInfo.sndNumTracks - audioHandleList After the multiple WAV files specified by audioHandleList are encoded, they are interleaved with the video data and output to a THP file. The specified THPAudioHandle structure must be opened with THPAudioCreateHandle. The number of lists must be as in audioInfo.sndNumTracks. NULL is specified when there is no audio conversion. *---------------------------------------------------------------------------*/ s32 THPUtyCreateTHP(FILE* op, s32 fileFlag, void* filePtr, THPFileHeader* fileHeader, THPAudioHandle** audioHandleList) { s32 rtn; s32 compInfoSize; u32 i, compCnt; THPFrameHeader frameHeader; u32* frameOffsetData = NULL; u32 frameHeaderSize; u32 frameSize; u32 frameSizeMax = 0; s32 frameSizeFirst = 0; s32 frameSizePrevious = 0; s32 movieDataSize = 0; u32 xSize, ySize; u8 tempZero[32]; s32 error = THP_ERROR_NOERROR; u32 NumFrames = fileHeader->header.numFrames; THPImageStatus imageStatus; THPFileHeader videoFileHeader; FILE* videoTHPFp; switch (fileHeader->videoInfo.videoType) { case THP_VIDEO_NON_INTERLACE: THPPrintLog("Video Type: [Non-interlace]\n"); break; case THP_VIDEO_ODD_INTERLACE: THPPrintLog("Video Type: [Interlace ODD start]\n"); break; case THP_VIDEO_EVEN_INTERLACE: THPPrintLog("Video Type: [Interlace EVEN start]\n"); break; } // // writing THPFileHeader // rtn = THPUtyWriteTHPFileHeader(op, fileHeader, &compInfoSize); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write THPFileHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // read the header from the original THP file (when adding/changing audio data) if (fileFlag == THP_CREATETHP_FILEFLAG_THP) { videoTHPFp = (FILE*)filePtr; rtn = THPUtyReadTHPFileHeader(videoTHPFp, &videoFileHeader); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't read THPFileHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // Seek movie data top rtn = fseek(videoTHPFp, videoFileHeader.header.movieDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } // // write offset data // // Note: frameOffsetData is an offset array from the second frame to the end of the last frame // however, procedurally, the array is set up from the first frame. When writing, it goes from the second frame. // frameOffsetData = (u32*)THPMalloc(sizeof(u32) * (NumFrames + 1)); if (frameOffsetData == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", sizeof(u32) * (NumFrames + 1), __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } if (fileHeader->header.offsetDataOffsets) { // A dummy write of the offset value. The actual offset value is written last. fileHeader->header.offsetDataOffsets = sizeof(THPFrameCompInfo) + fileHeader->header.compInfoDataOffsets + compInfoSize; rtn = fwrite(frameOffsetData, sizeof(u32) * NumFrames, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } // // all frame data is written // memset(tempZero, 0, sizeof(tempZero)); frameHeaderSize = sizeof(u32) * fileHeader->frameCompInfo.numComponents + sizeof(u32) * 2; THPPrintLog("START: Write THP Frame Datas.\n"); if (THPVerboseFlag == 0) { THPPrint(" << THP Packing START >>\r"); } else { THPPrint(" << THP Packing START >>\n"); } for (i = 0; i < NumFrames; i++) { s32 currPos; if (THPVerboseFlag == 0) { THPPrint(" Now Packing: No.%5ld/%5ld\r", i, NumFrames); } else { THPPrint(" Now Packing: No.%5ld/%5ld\n", i, NumFrames); } frameSize = frameHeaderSize; frameOffsetData[i] = (u32)ftell(op); if (frameOffsetData[i] == 0xFFFFFFFF) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } frameHeader.frameSizePrevious = frameSizePrevious; rtn = fseek(op, frameHeaderSize, SEEK_CUR); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } for (compCnt = 0; compCnt < fileHeader->frameCompInfo.numComponents; compCnt++) { // Write Frame switch (fileHeader->frameCompInfo.frameComp[compCnt]) { case THP_VIDEO_COMP: // Write Video Component if (fileFlag == THP_CREATETHP_FILEFLAG_JPEGS) { THPFileName* fileNameList = (THPFileName*)filePtr; rtn = THPUtyWriteVideoOneFrame(op, &fileNameList[i], &imageStatus); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write video data (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // Check Image Format if (i == 0) { xSize = imageStatus.xSize; ySize = imageStatus.ySize; } else if ((xSize != imageStatus.xSize) || (ySize != imageStatus.ySize)) { THPPrintError("\aERROR : Invalid x/y size (%ld)\n", __LINE__); THPPrintError(" All frames must have the same xsize\n"); THPPrintError(" and ysize with the 1st frame!!\n"); error = THP_ERROR_DATA; goto ERROR_END; } frameHeader.comp[compCnt] = imageStatus.imageSize; frameSize += imageStatus.imageSize; } else if (fileFlag == THP_CREATETHP_FILEFLAG_THP) { u32 videoFrameSize; rtn = THPUtyCopyVideoFrame(op, videoTHPFp, &videoFileHeader, &videoFrameSize); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write video data (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } frameHeader.comp[compCnt] = videoFrameSize; frameSize += videoFrameSize; } break; case THP_AUDIO_COMP: // Write Audio Component if (audioHandleList == NULL) { THPPrintError("\aERROR : Input audio file is not specified (%ld)\n", __LINE__); error = THP_ERROR_DATA; goto ERROR_END; } frameHeader.comp[compCnt] = THPAudioGetFrameSize(audioHandleList[0], i); rtn = THPUtyWriteAudioOneFrame(op, fileHeader, audioHandleList, frameHeader.comp[compCnt], i); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write audio data (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } frameSize += frameHeader.comp[compCnt] * fileHeader->audioInfo.sndNumTracks; break; case THP_NOCOMP_COMP: THPPrintError("\aERROR : Strange numComponents (%ld)\n", __LINE__); error = THP_ERROR_DATA; goto ERROR_END; break; default: THPPrintError("\aERROR : Unsupported Components (%ld)\n", __LINE__); error = THP_ERROR_DATA; goto ERROR_END; break; } } // 32Byte alignment if (frameSize % 32) { u32 remain = 32 - (frameSize % 32); rtn = fwrite(tempZero, remain, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } frameSize += remain; } // Get Current file position currPos = ftell(op); if (currPos == -1) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fseek(op, frameOffsetData[i], SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyWriteTHPFrameHeader(op, &fileHeader->frameCompInfo, &frameHeader); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write THPFrameHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } if (i == 0) { frameSizeFirst = frameSize; } else { // Update Previous THPFrameHeader.frameSizeNext rtn = fseek(op, frameOffsetData[i - 1], SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyPutU32(op, frameSize); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizeNext (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } } // Seek next frame top rtn = fseek(op, currPos, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } if (frameSize > frameSizeMax) { frameSizeMax = frameSize; } frameSizePrevious = frameSize; movieDataSize += frameSize; } THPPrint(" << THP Packing END >> \n"); THPPrintLog("END : Write THP Frame Datas.\n"); // // update THPFrameHeader.frameSizeNext for the final frame // rtn = fseek(op, frameOffsetData[NumFrames - 1], SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyPutU32(op, frameSizeFirst); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizeNext (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // update THPFileHeader // // Setup THPHeader fileHeader->header.version = THP_VERSION; fileHeader->header.bufSize = frameSizeMax; fileHeader->header.firstFrameSize = frameSizeFirst; fileHeader->header.movieDataSize = movieDataSize; fileHeader->header.finalFrameDataOffsets = frameOffsetData[NumFrames -1]; fileHeader->header.movieDataOffsets = frameOffsetData[0]; // Setup THPVideoInfo if (fileFlag == THP_CREATETHP_FILEFLAG_JPEGS) { fileHeader->videoInfo.xSize = imageStatus.xSize; fileHeader->videoInfo.ySize = imageStatus.ySize; } // Update THPHeader, THFrameCompInfo, THPVideoInfo, THPAudioInfo rtn = THPUtyWriteTHPFileHeader(op, fileHeader, NULL); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write THPFileHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // update THPFrameHeader.frameSizePrevious for the first frame // rtn = fseek(op, fileHeader->header.movieDataOffsets + sizeof(u32), SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyPutU32(op, frameSize); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizePrevious (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // write offset data // if (fileHeader->header.offsetDataOffsets) { THPPrintLog("START: Write THP Offset Data.\n"); THPPrint(" << Put Offset Data >>\n"); // frameOffsetData adjusts the value as it is the offset from the header of movidData. for (i = 1; i < NumFrames; i++) { frameOffsetData[i] = THPUtyReverseEndianU32(frameOffsetData[i] - frameOffsetData[0]); } frameOffsetData[NumFrames] = THPUtyReverseEndianU32(movieDataSize); // Update THPFrameOffsetData rtn = fseek(op, fileHeader->header.offsetDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fwrite(&frameOffsetData[1], sizeof(u32) * NumFrames, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } THPPrintLog("END : Write THP Offset Data.\n"); } ERROR_END: if (frameOffsetData != NULL) { THPFree(frameOffsetData); frameOffsetData = NULL; } return error; } /*---------------------------------------------------------------------------* Name: THPUtyChangeAudioTrack Description: Replaces the audio track for the THP file specified by iop with the audio specified by audioHandleList. Arguments: iop: a file pointer to the THPO file whose audio will be replaced fileHeader: a pointer to the THPFileHeader storing the THP header information audioHandleList: a list of pointers for handles for the replacement audio There must be as many arrays as the value in fileHeader.audioInfo.sndNumTracks, with NULL in arrays corresponding to tracks that are not to be replaced. Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read/write failure THP_ERROR_THPFILE: THP file error *---------------------------------------------------------------------------*/ s32 THPUtyChangeAudioTrack(FILE* iop, THPFileHeader* fileHeader, THPAudioHandle** audioHandleList) { s32 rtn; s32 error = THP_ERROR_NOERROR; u32 i; u32 frameHeaderSize; // checks the existence of the audio track if ((fileHeader->audioInfo.sndChannels == 0) || (fileHeader->audioInfo.sndFrequency == 0)) { THPPrintError("\aERROR : This file doesn't have audio data (%ld)\n", __LINE__); error = THP_ERROR_THPFILE; goto ERROR_END; } // moves to the first frame rtn = fseek(iop, fileHeader->header.movieDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // gets the size of the frame header frameHeaderSize = sizeof(u32) * fileHeader->frameCompInfo.numComponents + sizeof(u32) * 2; THPPrintLog("START: Write THP Frame Datas.\n"); if (THPVerboseFlag == 0) { THPPrint(" << THP Restructuring START >>\r"); } else { THPPrint(" << THP Restructuring START >>\n"); } // // Replace the audio data at each frame // for (i = 0; i < fileHeader->header.numFrames; i++) { THPFrameHeader frameHeader; u32 compCnt; s32 framePos; u32 frameSize; if (THPVerboseFlag == 0) { THPPrint(" Now Restructuring: No.%5ld/%5ld\r", i, fileHeader->header.numFrames); } else { THPPrint(" Now Restructuring: No.%5ld/%5ld\n", i, fileHeader->header.numFrames); } // gets the current file position framePos = ftell(iop); if (framePos == -1) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // gets THPFrameHeader rtn = THPUtyReadTHPFrameHeader(iop, &frameHeader, fileHeader->frameCompInfo.numComponents); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't read THPFrameHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } frameSize = frameHeaderSize; for (compCnt = 0; compCnt < fileHeader->frameCompInfo.numComponents; compCnt++) { switch (fileHeader->frameCompInfo.frameComp[compCnt]) { case THP_VIDEO_COMP: // video data is skipped rtn = fseek(iop, frameHeader.comp[compCnt], SEEK_CUR); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } frameSize += frameHeader.comp[compCnt]; break; case THP_AUDIO_COMP: // audio data is overwritten rtn = THPUtyWriteAudioOneFrame(iop, fileHeader, audioHandleList, frameHeader.comp[compCnt], i); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write audio data (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } frameSize += frameHeader.comp[compCnt] * fileHeader->audioInfo.sndNumTracks; break; case THP_NOCOMP_COMP: THPPrintError("\aERROR : Strange numComponents (%ld)\n", __LINE__); error = THP_ERROR_THPFILE; goto ERROR_END; break; default: THPPrintError("\aERROR : Unsupported Components (%ld)\n", __LINE__); error = THP_ERROR_THPFILE; goto ERROR_END; break; } } // moves to the next frame frameSize = (frameSize + 31) & ~31; rtn = fseek(iop, framePos + frameSize, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } THPPrint(" << THP Restructuring END >> \n"); THPPrintLog("END : Write THP Frame Datas.\n"); ERROR_END: return error; } /*---------------------------------------------------------------------------* Name: THPUtyCopyTHPFile Description: copies the THP file specified by ip to op Arguments: ip: a file pointer to the source THP file fileHeader: a pointer to the THPFileHeader structure op: a file pointer to the target THP file Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read/write failure THP_ERROR_DATA: data error THP_ERROR_FATAL: memory allocation failure *---------------------------------------------------------------------------*/ #define THPUTY_COPY_SIZE 0x100000 #define THPUTY_MAX_PADDING_SIZE 32 s32 THPUtyCopyTHPFile(FILE* ip, THPFileHeader* fileHeader, FILE* op) { s32 rtn; s32 error = THP_ERROR_NOERROR; u8* tmp_buffer = NULL; u32* frame_offsets = NULL; // // when the source THP file is version 1.10 or later // if (fileHeader->header.version > 0x10000) { u32 file_size; u32 read_size; u32 wrote_size = 0; // Allocate the temporary buffer tmp_buffer = (u8*)THPMalloc(THPUTY_COPY_SIZE); if (tmp_buffer == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", THPUTY_COPY_SIZE, __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } // gets the file size rtn = fseek(ip, 0, SEEK_END); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } file_size = ftell(ip); if (file_size == -1L) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fseek(ip, 0, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // copies the file as is while (wrote_size < file_size) { if (file_size - wrote_size < THPUTY_COPY_SIZE) { read_size = file_size - wrote_size; } else { read_size = THPUTY_COPY_SIZE; } rtn = fread(tmp_buffer, read_size, 1, ip); if(rtn != 1) { THPPrintError("\aERROR : fread error (%ld)", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fwrite(tmp_buffer, read_size, 1, op); if(rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } wrote_size += read_size; } if (fileHeader->header.offsetDataOffsets) { THPPrint(" << Put Offset Data >>\n"); } } // // when the source THP file is version 1.00 or older // else { u32 ii, jj; u32 num_frames; s32 compinfo_size; u32 old_size; u32 frame_size; u32 prev_size = 0; u32 first_size; u32 max_size = 0; u32 total_size = 0; u32 remain; u32 tmp_loc; u8 zero_buffer[THPUTY_MAX_PADDING_SIZE]; THPFrameHeader* frame_header; // moves the file pointer to the first frame data rtn = fseek(ip, fileHeader->header.movieDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // // writing THPFileHeader // rtn = THPUtyWriteTHPFileHeader(op, fileHeader, &compinfo_size); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write THPFileHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // A dummy write of the offset value. The actual offset value is written last. // // Note: The offset data is an offset array from the second frame to the end of the last frame, but the array is prepared starting with the first frame to make the processing convenient. When writing, it goes from the second frame. // // // // gets the number of frames num_frames = fileHeader->header.numFrames; frame_offsets = (u32*)THPMalloc(sizeof(u32) * (num_frames + 1)); if (frame_offsets == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", sizeof(u32) * (num_frames + 1), __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } if (fileHeader->header.offsetDataOffsets) { fileHeader->header.offsetDataOffsets = fileHeader->header.compInfoDataOffsets + sizeof(THPFrameCompInfo) + compinfo_size; rtn = fwrite(frame_offsets, sizeof(u32) * num_frames, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } // // all frame data is written // // initializes the padding data memset(zero_buffer, 0, sizeof(zero_buffer)); // gets the old size of the first frame old_size = fileHeader->header.firstFrameSize; for (ii = 0; ii < num_frames; ii++) { // gets the offset information frame_offsets[ii] = (u32)ftell(op); if (frame_offsets[ii] == 0xFFFFFFFF) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // allocates a region for reading tmp_buffer = THPMalloc(old_size + THPUTY_MAX_PADDING_SIZE); if (tmp_buffer == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", (old_size + THPUTY_MAX_PADDING_SIZE), __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } // reading the frame data rtn = fread(tmp_buffer, old_size, 1, ip); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // gets the frame size without padding frame_header = (THPFrameHeader *)tmp_buffer; frame_size = sizeof(u32) * (2 + fileHeader->frameCompInfo.numComponents); for (jj = 0; jj < fileHeader->frameCompInfo.numComponents; jj++) { frame_size += THPUtyReverseEndianU32(frame_header->comp[jj]); } // gets the size of the next frame old_size = THPUtyReverseEndianU32(frame_header->frameSizeNext); // updates the frame header (1) - frameSizePrevious frame_header->frameSizePrevious = THPUtyReverseEndianU32(prev_size); // writes the frame data rtn = fwrite(tmp_buffer, frame_size, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // re-padding if (frame_size % 32) { remain = 32 - (frame_size % 32); rtn = fwrite(zero_buffer, remain, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } frame_size += remain; } // Deallocates a region for reading THPFree(tmp_buffer); tmp_buffer = NULL; // updates the frame header (2) - frameSizeNext if (ii != 0) { tmp_loc = ftell(op); // rewind the file pointer to the top of the previous frame data rtn = fseek(op, frame_offsets[ii - 1], SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } // write the current frame size (frameSizeNext is the header) rtn = THPUtyPutU32(op, frame_size); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizeNext (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // return the file pointer to the end of the current frame data rtn = fseek(op, tmp_loc, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } // size inheritance prev_size = frame_size; // update first size, reflecting it to THPHeader.firstFrameSize if (ii == 0) { first_size = frame_size; } // update max size, reflecting it to THPHeader.bufSize if (frame_size > max_size) { max_size = frame_size; } // update total size, reflecting it to THPHeader.movieDataSize total_size += frame_size; } // // update THPFrameHeader.frameSizePrevious for the first frame // rtn = fseek(op, frame_offsets[0] + sizeof(u32), SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyPutU32(op, frame_size); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizePrevious (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // update THPFrameHeader.frameSizeNext for the final frame // rtn = fseek(op, frame_offsets[num_frames - 1], SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyPutU32(op, first_size); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write frameSizeNext (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // update THPHeader // fileHeader->header.version = THP_VERSION; fileHeader->header.bufSize = max_size; fileHeader->header.firstFrameSize = first_size; fileHeader->header.movieDataSize = total_size; fileHeader->header.movieDataOffsets = frame_offsets[0]; fileHeader->header.finalFrameDataOffsets = frame_offsets[num_frames -1]; rtn = THPUtyWriteTHPFileHeader(op, fileHeader, NULL); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't write THPFileHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } // // writes the offset data // if (fileHeader->header.offsetDataOffsets) { THPPrint(" << Put Offset Data >>\n"); // the offset data for each frame is the offset value from the first frame for (ii = 1; ii < num_frames; ii++) { frame_offsets[ii] = THPUtyReverseEndianU32(frame_offsets[ii] - frame_offsets[0]); } frame_offsets[num_frames] = THPUtyReverseEndianU32(total_size); rtn = fseek(op, fileHeader->header.offsetDataOffsets, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fwrite(&frame_offsets[1], sizeof(u32) * num_frames, 1, op); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } } ERROR_END: if (tmp_buffer) { THPFree(tmp_buffer); } if (frame_offsets) { THPFree(frame_offsets); } return error; } /*---------------------------------------------------------------------------* *---------------------------------------------------------------------------* * Local Functions * *---------------------------------------------------------------------------* *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: THPUtyWriteVideoOneFrame Description: Reads the JPEG file specified by fileName, converts it to THP format, and outputs it to the file specified by thpFp. Arguments: thpFp: a file pointer to the THP file to be output fileName: the file name for the JPG file to be converted imageStatus: a pointer to the THPImageStatus structure storing the converted image information Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read/write failure THP_ERROR_JPEGFILE: JPG file error THP_ERROR_FATAL: memory allocation failure *---------------------------------------------------------------------------*/ static s32 THPUtyWriteVideoOneFrame(FILE* thpFp, THPFileName* fileName, THPImageStatus* imageStatus) { FILE* jpegFp = NULL; u8* jpegBuffer = NULL; u8* thpBuffer = NULL; s32 error = THP_ERROR_NOERROR; s32 rtn; jpegBuffer = (u8*)THPMalloc(fileName->fileSize); if (jpegBuffer == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", fileName->fileSize, __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } thpBuffer = (u8*)THPMalloc(fileName->fileSize * 2); if (thpBuffer == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", fileName->fileSize * 2, __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } jpegFp = fopen(fileName->name, "rb"); if (jpegFp == NULL) { THPPrintError("\aERROR : Can't open [%s] file (%ld)\n", fileName->name, __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fread(jpegBuffer, fileName->fileSize, 1, jpegFp); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } fclose(jpegFp); jpegFp = NULL; rtn = THPConvertJPEG2THP(jpegBuffer, thpBuffer, fileName->fileSize, imageStatus); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't convert [%s] file to THP (%ld)\n", fileName->name, __LINE__); error = rtn; goto ERROR_END; } while (imageStatus->imageSize % 4) { *(thpBuffer + imageStatus->imageSize) = 0x00; imageStatus->imageSize++; } rtn = fwrite(thpBuffer, imageStatus->imageSize, 1, thpFp); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } ERROR_END: if (jpegBuffer != NULL) { THPFree(jpegBuffer); } if (thpBuffer != NULL) { THPFree(thpBuffer); } if (jpegFp != NULL) { fclose(jpegFp); } return error; } /*---------------------------------------------------------------------------* Name: THPUtyWriteAudioOneFrame Description: Encodes the first frame's worth of multiple audio specified by audioHandleList and outputs it to the file specified by thpFp. Only the frameSize portion is sought for NULL array elements in the audioHandleList. Arguments: thpFp: a file pointer to the THP file to be output fileHeader: a pointer to the THPFileHeader structure audioHandleList: a pointer array for THPAudioHandle The array number must be as in fileHeader.audioInfo.sndNumTracks. frameSize: the size of the audio for the first frame frameNum: the frame number Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file output failed *---------------------------------------------------------------------------*/ static s32 THPUtyWriteAudioOneFrame(FILE* thpFp, THPFileHeader* fileHeader, THPAudioHandle** audioHandleList, u32 frameSize, u32 frameNum) { u32 cnt; u32 flag; s32 error = THP_ERROR_NOERROR; flag = (frameNum == (fileHeader->header.numFrames - 1)) ? 1 : 0; for (cnt = 0; cnt < fileHeader->audioInfo.sndNumTracks; cnt++) { if (audioHandleList[cnt] == NULL) { u32 rtn; rtn = fseek(thpFp, frameSize, SEEK_CUR); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } else { if (THPAudioWriteFrame(audioHandleList[cnt], thpFp, flag) == FALSE) { THPPrintError("\aERROR : Can't convert [%s] file to THP Audio (%ld)\n", audioHandleList[cnt]->audioInfo.fileName, __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } } } ERROR_END: return error; } /*---------------------------------------------------------------------------* Name: THPUtyCopyVideoFrame Description: Copies the video data from the THP file specified by videoTHPFp to the file specified by thpFp. Arguments: thpFp: a file pointer to the video data copy target videoTHPFp: a file pointer to the copy source video data videoFileHeader: the header of the copy source THP file videoCompSize: a pointer to the stored size of the copied video data Returns: THP_ERROR_NOERROR: normal termination THP_ERROR_FILEIO: file read/write failure THP_ERROR_THPFILE: THP file error THP_ERROR_FATAL: memory allocation failure *---------------------------------------------------------------------------*/ static s32 THPUtyCopyVideoFrame(FILE* thpFp, FILE* videoTHPFp, THPFileHeader* videoFileHeader, u32* videoCompSize) { u8* buffer = NULL; u32 compCnt; s32 rtn; s32 error = THP_ERROR_NOERROR; u32 framePos; u32 frameSize; THPFrameHeader frameHeader; framePos = ftell(videoTHPFp); if (framePos == -1) { THPPrintError("\aERROR : ftell error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = THPUtyReadTHPFrameHeader(videoTHPFp, &frameHeader, videoFileHeader->frameCompInfo.numComponents); if (rtn != THP_ERROR_NOERROR) { THPPrintError("\aERROR : Can't read THPFrameHeader (%ld)\n", __LINE__); error = rtn; goto ERROR_END; } frameSize = sizeof(u32) * videoFileHeader->frameCompInfo.numComponents + sizeof(u32) * 2; for (compCnt = 0; compCnt < videoFileHeader->frameCompInfo.numComponents; compCnt++) { switch (videoFileHeader->frameCompInfo.frameComp[compCnt]) { case THP_VIDEO_COMP: buffer = (u8*)THPMalloc(frameHeader.comp[compCnt]); if (buffer == NULL) { THPPrintError("\aERROR : Can't allocate memory (%ld Bytes) (%ld)\n", frameHeader.comp[compCnt], __LINE__); error = THP_ERROR_FATAL; goto ERROR_END; } rtn = fread(buffer, frameHeader.comp[compCnt], 1, videoTHPFp); if (rtn != 1) { THPPrintError("\aERROR : fread error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } rtn = fwrite(buffer, frameHeader.comp[compCnt], 1, thpFp); if (rtn != 1) { THPPrintError("\aERROR : fwrite error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } THPFree(buffer); buffer = NULL; frameSize += frameHeader.comp[compCnt]; if (videoCompSize != NULL) { *videoCompSize = frameHeader.comp[compCnt]; } break; case THP_AUDIO_COMP: frameSize += frameHeader.comp[compCnt] * videoFileHeader->audioInfo.sndNumTracks; break; case THP_NOCOMP_COMP: THPPrintError("\aERROR : Strange numComponents (%ld)\n", __LINE__); error = THP_ERROR_THPFILE; goto ERROR_END; break; default: THPPrintError("\aERROR : Unsupported Components (%ld)\n", __LINE__); error = THP_ERROR_THPFILE; goto ERROR_END; break; } } frameSize = (frameSize + 31) & ~31; rtn = fseek(videoTHPFp, framePos + frameSize, SEEK_SET); if (rtn != 0) { THPPrintError("\aERROR : fseek error (%ld)\n", __LINE__); error = THP_ERROR_FILEIO; goto ERROR_END; } ERROR_END: if (buffer != NULL) { THPFree(buffer); buffer = NULL; } return error; }