#include "rm_avirepair.h" #include "rm_constants.h" #include #include #include #include #ifdef Q_OS_WIN #include #endif //#include "rm_fileio.h" // Sub title 확인해서 처리해야 할 경우 #if (REPAIR_CHECK_SUBTITLE) #include "rm_videogroup.h" #include "rm_sensordata.h" #if (RM_USE_SEPARATED_CH_FILE) #include "rm_videoitem_2ch.h" #else #include "rm_videoitem.h" #endif #endif class RMFileIO { private: #ifdef Q_OS_WIN HANDLE _f; #else FILE* _f; #endif QString _filePath; public: RMFileIO(QString& filePath, bool readOnly = false); ~RMFileIO(); bool isValid() { return (_f != NULL); } QString filePath() { return _filePath; } size_t GetLength(); size_t Read(void* buffer, size_t length); void Close(); void Seek(long _Offset, int _Origin); void Write(void* buffer, size_t length); void SetLength(size_t length); size_t GetPosition(); static bool Rename(QString& oldName, QString& newName); static QString ReplaceFileNameOnly(const QString& src, const QString& search, const QString& replace); }; // 파일명만 변경함 QString RMFileIO::ReplaceFileNameOnly(const QString& src, const QString& search, const QString& replace) { QFileInfo info = QFileInfo(src); return QDir::cleanPath(info.dir().absolutePath() + QDir::separator() + info.baseName().replace(search,replace,Qt::CaseInsensitive) + "." + info.suffix()); } bool RMFileIO::Rename(QString& oldName, QString& newName) { #ifdef Q_OS_WIN // return ::MoveFileExW((LPCTSTR)oldName.utf16(),(LPCTSTR)newName.utf16(),MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH); QString oldWin = oldName.replace("/","\\"); QString newWin = newName.replace("/","\\"); if (::MoveFile((LPCTSTR)oldWin.utf16(), (LPCTSTR)newWin.utf16()) == FALSE) { qInfo() << "GetLastError():" << ::GetLastError(); qInfo() << "filePath:" << oldWin; qInfo() << "destPath:" << newWin; } return TRUE; #else return QFile::rename(oldName,newName); #endif } RMFileIO::RMFileIO(QString& filePath, bool readOnly) { _f = NULL; _filePath = filePath; #ifdef Q_OS_WIN if(readOnly == true) { _f = ::CreateFile((LPCTSTR)_filePath.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { _f = ::CreateFile((LPCTSTR)_filePath.utf16(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } #else _f = fopen(_filePath.toLocal8Bit(),"r+b"); #endif } RMFileIO::~RMFileIO() { Close(); } size_t RMFileIO::GetLength() { #ifdef Q_OS_WIN return (size_t)::GetFileSize(_f,NULL); #else long cur = ftell(_f); fseek(_f, 0L, SEEK_END); size_t fileSize = ftell(_f); fseek(_f, cur, SEEK_SET); return fileSize; #endif } size_t RMFileIO::Read(void* buffer, size_t length) { #ifdef Q_OS_WIN DWORD dwRead = 0; if(::ReadFile(_f,buffer,length,&dwRead,NULL) == FALSE) { return 0; } return (size_t)dwRead; #else return fread(buffer,1,length,_f); #endif } void RMFileIO::Write(void* buffer, size_t length) { #ifdef Q_OS_WIN DWORD dwWrite = 0; ::WriteFile(_f,buffer,length,&dwWrite,NULL); #else fwrite(buffer,1,length,_f); #endif } void RMFileIO::SetLength(size_t length) { #if (NO_FILE_RESIZE) Q_UNUSED(length) #else #ifdef Q_OS_WIN ::SetFilePointer(_f,length,NULL,FILE_BEGIN); ::SetEndOfFile(_f); #else _chsize(fileno(_f),(long)length); #endif #endif // #if (!NO_FILE_RESIZE) } size_t RMFileIO::GetPosition() { #ifdef Q_OS_WIN size_t position = (size_t)::SetFilePointer(_f,0,NULL,FILE_CURRENT); return position; #else return ftell(_f); #endif } void RMFileIO::Close() { #ifdef Q_OS_WIN if(_f != NULL) { ::CloseHandle(_f); _f = NULL; } #else if(_f != NULL) { fclose(_f); _f = NULL; } #endif } void RMFileIO::Seek(long _Offset, int _Origin) { #ifdef Q_OS_WIN DWORD method = FILE_BEGIN; // SEEK_SET if(_Origin == SEEK_CUR) { method = FILE_CURRENT; } else if (_Origin == SEEK_END) { method = FILE_END; } ::SetFilePointer(_f,_Offset,NULL,method); #else fseek(_f,_Offset,_Origin); #endif } #ifndef FCC #if (_MSC_VER) #define FCC(ch4) ((((DWORD)(ch4) & 0xFF) << 24) | \ (((DWORD)(ch4) & 0xFF00) << 8) | \ (((DWORD)(ch4) & 0xFF0000) >> 8) | \ (((DWORD)(ch4) & 0xFF000000) >> 24)) #else // _MSC_VER #define FCC(ch4) ((((uint32_t)(size_t)(ch4) & 0xFF) << 24) | \ (((uint32_t)(size_t)(ch4) & 0xFF00) << 8) | \ (((uint32_t)(size_t)(ch4) & 0xFF0000) >> 8) | \ (((uint32_t)(size_t)(ch4) & 0xFF000000) >> 24)) #endif // _MSC_VER #endif //#if (RM_MODEL == RM_MODEL_TYPE_TELEBIT) //#define MANDO_TB2000 1 //#endif //#ifdef MANDO_TB2000 //#define _ENCRYPT_SIZE 0xdc //static BYTE *stc_pu8Data = NULL; ////static void efs_file_decrypt(FILE *fp) //static void efs_file_decrypt(RMFileIO& file) //{ // int i = 0; // BYTE *temp = NULL; // int length = _ENCRYPT_SIZE; // int j = length - 1; // if(stc_pu8Data == NULL) // { // stc_pu8Data = new BYTE [_ENCRYPT_SIZE]; // } // temp = new BYTE [_ENCRYPT_SIZE]; // file.Read(stc_pu8Data,_ENCRYPT_SIZE); //// fread(stc_pu8Data, _ENCRYPT_SIZE, 1, fp); //#if 0 // temp[0] = (((stc_pu8Data[(size - 1)] & 0x0F) << 4) | ((stc_pu8Data[0] & 0xF0) >> 4)); // for(i = 1; i < size; i++) // { // temp[i] = (((stc_pu8Data[i-1] & 0x0F) << 4) | ((stc_pu8Data[i] & 0xF0) >> 4)); // } //#else // temp[0] = (((stc_pu8Data[(length - 1)] & 0x1F) << 3) | ((stc_pu8Data[0] & 0xE0) >> 5)); // for(i = 1; i < length; i++) // { // temp[i] = (((stc_pu8Data[i-1] & 0x1F) << 3) | ((stc_pu8Data[i] & 0xE0) >> 5)); // } //#endif // if(((temp[j] ^ 0xFF) == 'R') && ((temp[j-1] ^ 0xFF) == 'I') && ((temp[j-2] ^ 0xFF) == 'F') && ((temp[j-3] ^ 0xFF) == 'F')) // { // for(i = 0; i < length; i++) // { // stc_pu8Data[i] = temp[j--] ^ 0xFF; // } // } // file.Seek(0,SEEK_SET); //// fseek(fp, 0, SEEK_SET); // delete [] temp; //} //void efs_file_encrypt(BYTE *pu8Data, int length) //{ // int i = 0; // BYTE *temp = NULL; // int j = length - 1; // temp = new BYTE [length]; // if(pu8Data[0] == 'R' && pu8Data[1] == 'I' && pu8Data[2] == 'F' && pu8Data[3] == 'F') // { // for(i = 0; i < length; i++) // { // temp[j--] = pu8Data[i] ^ 0xFF; // } //#if 0 // for(i = 0; i < (length - 1); i++) // { // pu8Data[i] = (((temp[i] & 0x0F) << 4) | ((temp[i+1] & 0xF0) >> 4)); // } // pu8Data[(length - 1)] = (((temp[(length - 1)] & 0x0F) << 4) | ((temp[0] & 0xF0) >> 4)); //#else // for(i = 0; i < (length - 1); i++) // { // pu8Data[i] = (((temp[i] & 0x07) << 5) | ((temp[i+1] & 0xF8) >> 3)); // } // pu8Data[(length - 1)] = (((temp[(length - 1)] & 0x07) << 5) | ((temp[0] & 0xF8) >> 3)); //#endif // } // delete [] temp; //} //#endif // MANDO_TB2000 #include static uint32_t GET_FCC (FILE *fp) { unsigned char tmp[4] = {0,}; //#ifdef MANDO_TB2000 // int offset = (int)ftell(fp); // if(offset < _ENCRYPT_SIZE) // { // tmp[0] = stc_pu8Data[offset++]; // tmp[1] = stc_pu8Data[offset++]; // tmp[2] = stc_pu8Data[offset++]; // tmp[3] = stc_pu8Data[offset++]; // fseek(fp, offset, SEEK_SET); // return FCC (tmp); // } //#endif // MANDO_TB2000 tmp[0] = getc(fp); tmp[1] = getc(fp); tmp[2] = getc(fp); tmp[3] = getc(fp); return FCC (tmp); } static unsigned int GET_TCC (FILE *fp) { char tmp[5] = {0,}; //#ifdef MANDO_TB2000 // int offset = (int)ftell(fp); // if(offset < _ENCRYPT_SIZE) // { // tmp[0] = stc_pu8Data[offset++]; // tmp[1] = stc_pu8Data[offset++]; // tmp[2] = 0; // tmp[3] = 0; // fseek(fp, offset, SEEK_SET); // return FCC (tmp); // } //#endif tmp[0] = getc(fp); tmp[1] = getc(fp); tmp[2] = 0; tmp[3] = 0; return FCC (tmp); } #define RECOVERY_MAX_COUNT 8000 #define FILE_SIZE_INDEX 0x0004 #define MICORSECPERFRMAE_INDEX 0x0020 // 2018-09-12 추가 #define MAX_TRANSFER_RATE_INDEX 0x0024 #define TOTAL_FRAME_INDEX 0x0030 #define AVIH_FLAG_INDEX 0x002C // 2018-09-12 추가 #define STREAM_COUNT_INDEX 0x0038 #define BUFFER_SIZE_INDEX 0x003C #define VIDEO_WIDTH_INDEX 0x0040 #define VIDEO_HEIGHT_INDEX 0x0044 #if 0 typedef DWORD FOURCC typedef struct { FOURCC fccType; //4 FOURCC fccHandler; //8 DWORD dwFlags; //12 WORD wPriority; //14 WORD wLanguage; //16 DWORD dwInitialFrames; //20 DWORD dwScale; //24 DWORD dwRate; /*28*//* dwRate / dwScale == samples/second */ DWORD dwStart; //32 DWORD dwLength; /* In units above... */ DWORD dwSuggestedBufferSize; DWORD dwQuality; DWORD dwSampleSize; RECT rcFrame; } AVIStreamHeader; #endif #define STREAM_LENGTH_INDEX 32 //0x008C #define STREAM_SCALE_INDEX 20 //0x017C #define STREAM_RATE_INDEX 24 //0x017C #define STREAM_SAMPLERATE_INDEX 68 #define STREAM_AUDIO_CHANNEL_INDEX 66 // 2018/09/04 버전에서 추가됨 -> H265 AVI 만 적용 #define STREAM_TEXT_BUFFER_INDEX 36 // " typedef struct _idx1_data_s { unsigned int nCkID; unsigned int nFlags; unsigned int nOffset; unsigned int nLength; } _idx1_data_t; #define STREAM_VIDEO_0 0x01 #define STREAM_VIDEO_1 0x02 #define STREAM_AUDIO_0 0x04 #define STREAM_TEXT_0 0x08 #define AVI_STREAM_MAX 4 // 2018/09/04 버전에서 추가됨 -> H265 AVI 만 적용 typedef struct _idx1_frame_s { unsigned short nCkID; unsigned short nFrame; } _idx1_frame_t; typedef struct _idx1_info_s { unsigned char szIdx1[4]; unsigned int size; _idx1_data_t idx_data[RECOVERY_MAX_COUNT]; _idx1_frame_t frame_list[RECOVERY_MAX_COUNT]; //unsigned char nCkID[RECOVERY_MAX_COUNT]; } _idx1_info_t; /* Flags for AVI_INDEX_ENTRY */ #define AVIIF_LIST 0x00000001L #define AVIIF_TWOCC 0x00000002L /* keyframe doesn't need previous info to be decompressed */ #define AVIIF_KEYFRAME 0x00000010L /* this chunk needs the frames following it to be used */ #define AVIIF_FIRSTPART 0x00000020L /* this chunk needs the frames before it to be used */ #define AVIIF_LASTPART 0x00000040L #define AVIIF_MIDPART (AVIIF_LASTPART|AVIIF_FIRSTPART) /* this chunk doesn't affect timing ie palette change */ #define AVIIF_NOTIME 0x00000100L #define AVIIF_COMPUSE 0x0FFF0000L #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) enum { CHIP_A20 = 0, //AVI type2 CHIP_V35, //AVI type1 #if 0 MODEL_KV100 = 0, MODEL_KH100, MODEL_KP100, #endif MODEL_MAX }; //inline DWORD RMGetFileSize(FILE* f) //{ // long cur = ftell(f); // fseek(f, 0L, SEEK_END); // DWORD fileSize = (DWORD)ftell(f); // fseek(f, cur, SEEK_SET); // return fileSize; //} // file.Read(byTemp, 4); inline size_t RMReadFile(FILE* f,unsigned char* buffer, uint32_t length) { return fread(buffer,length,1,f); } RMAVIRepair::RMAVIRepair(QObject *parent) : QObject(parent) { } #if (REPAIR_FAILED_TAG) void RMAVIRepair::rename_failed(QString& filePath) { QFileInfo* fileInfo = new QFileInfo(filePath); #if (RM_IS_COMTEC) QString fileName = fileInfo->fileName().replace("_SDEXIT","_f",Qt::CaseInsensitive);; #else QString fileName = fileInfo->fileName().replace("_EXIT","_f",Qt::CaseInsensitive);; #endif QString destPath = fileInfo->absoluteDir().path() + PATH_COMPONENT + fileName; delete fileInfo; RMFileIO::Rename(filePath,destPath); } #endif #if (REPAIR_CHECK_SUBTITLE) // 파일명과 비교하여 bool RMAVIRepair::compare_subtitle_time(QString& filePath, char* subtitle) { // 발생할 수 없음 QDateTime fileTime; if(RMVideoItem::IsFeasible(filePath,&fileTime) == RMVideoGroup::TYPE_UNDEFINED) { return false; } // ZDR026:2018-03-03 21:17:50 X: 0.00 Y: 0.00 Z: 0.00 000.0T 0.0V - --.------ - ---.------ - ---.-km/h E:255 M:255 EM:255 SA:0 // qInfo() << subtitle; NMEA_INFO info = {0,}; if(RMSensorData::parse_subtitle_time(subtitle,&info)) { QDateTime subtitleDate(QDate(info.nYear,info.nMonth,info.nDay),QTime(info.nHour,info.nMin,info.nSec)); //qInfo() << subtitleDate << ":" << fileTime; //qInfo() << "SEC TO:" << subtitleDate.secsTo(fileTime) << " or " << fileTime.secsTo(subtitleDate); return abs(subtitleDate.secsTo(fileTime)) < 1800; // 30분 미만 } return true; } #endif #if(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || SUPPORT_AVI_FIX_DURL) #if (SUPPORT_AVI_FIX_DURL) // 통합 뷰어의 경우 ZDR-TYPE05/06 동시 지원 bool RMAVIRepair::repairV50(QString& filePath, QString& destPath) #else bool RMAVIRepair::repair(QString& filePath, QString& destPath) #endif { RMFileIO file = RMFileIO(filePath); if(file.isValid() == false) { return false; } #ifdef MANDO_TB2000 efs_file_decrypt(file); if(stc_pu8Data == NULL) { return false; } #endif unsigned char *pData = NULL; unsigned int nVideo1Count = 0; unsigned int nVideo2Count = 0; unsigned int nAudioCount = 0; unsigned int nFrameCount = 0; unsigned int nFrameSize = 0; unsigned int nFileSize = 0; unsigned int nIdxOffset = 0; unsigned long i = 0; unsigned int nMoviSize = 0; unsigned int nAudioLength = 0; unsigned int nTextLength = 0; unsigned int nMaxTransRate = 0; unsigned int nAudioRate = 44101;//????? unsigned int nAudioScale = 2; unsigned int nAudioSampleRate = 44100; unsigned int nAudioChannel = 1; _idx1_info_t idx_info, *pIdx_info; unsigned char byTemp[10]; unsigned int nTagName = 0; unsigned int nListSize = 0; unsigned int nListOffset = 0; unsigned char bFindMovi = false; unsigned int nStrhPos[AVI_STREAM_MAX] = { 0, 0, 0, 0 }; unsigned int nStreamCount = 0; uint32_t dwFileSize = 0; int nVideoId[2] = { -1, -1 }; int nSoundId = -1; int nTxtId = -1; unsigned int nAvihFlag = 0x00010010; unsigned int nBufferSize = 192000; unsigned int nFileWitdh = 2560; unsigned int nFileHeight = 1440; unsigned int nTextBufferSize = 0x20; unsigned int nMicorSecPerFrmae = 0; unsigned char bFindVidStream = 0; pIdx_info = &idx_info; memset(pIdx_info, 0x00, sizeof(_idx1_info_t)); memcpy(pIdx_info->szIdx1, "idx1", 4); dwFileSize = (uint32_t)file.GetLength(); file.Read(byTemp, 4); #ifdef MANDO_TB2000 if(memcmp(stc_pu8Data, "RIFF", 4)) { return FALSE; } memcpy(&nFileSize, &stc_pu8Data[4], 4); if(dwFileSize == (nFileSize + 8)) { file.Close(); return true; } #else // MANDO_TB2000 if(memcmp(byTemp, "RIFF", 4)) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } file.Read(&nFileSize, 4); if(dwFileSize == (nFileSize + 8)) { file.Close(); return true; } #endif // MANDO_TB2000 file.Seek(12, SEEK_SET); nListOffset = 12; #ifdef MANDO_TB2000 while(1) { if(nListOffset < _ENCRYPT_SIZE) { memcpy(byTemp, &stc_pu8Data[nListOffset], 8); } else { if(8 != file.Read(byTemp, 8)) break; } #else // MANDO_TB2000 while(8 == file.Read(byTemp, 8)) { #endif // MANDO_TB2000 memcpy(&nTagName, &byTemp[0], 4); memcpy(&nListSize, &byTemp[4], 4); nListOffset += 8; if(nTagName == MKTAG('L','I','S','T')) { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nTagName, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nTagName, 4); nListOffset += 4; if (nTagName == MKTAG('m','o','v','i')) { bFindMovi = true; break; } else if (nTagName == MKTAG('h','d','r','l')) { } else if (nTagName == MKTAG('s','t','r','l')) { } else { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nListSize, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nListSize, 4); nListOffset += nListSize; } } else if(nTagName == MKTAG('s','t','r','h')) { if(nStreamCount < AVI_STREAM_MAX) { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nTagName, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nTagName, 4); switch(nTagName) { case MKTAG('v','i','d','s') : if(nVideoId[0] == -1) { unsigned int nVideoScale = 0; unsigned int nVideoRate = 0; file.Seek(16, SEEK_CUR); #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nVideoScale, &stc_pu8Data[nListOffset+4+16], 4); else #endif file.Read(&nVideoScale, 4); #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nVideoRate, &stc_pu8Data[nListOffset+4+16+4], 4); else #endif file.Read(&nVideoRate, 4); nVideoId[0] = nStreamCount; bFindVidStream = 1; } else { nVideoId[1] = nStreamCount; } nStrhPos[nStreamCount++] = nListOffset; break; case MKTAG('a','u','d','s') : // 적용완료 nSoundId = nStreamCount; nStrhPos[nStreamCount++] = nListOffset; // STREAM_SCALE_INDEX = 20 #if (_MSC_VER) file.Seek(STREAM_SCALE_INDEX-4,FILE_CURRENT); // TAG READ 4 BYTE 빼고 SEEK #else file.Seek(STREAM_SCALE_INDEX-4,SEEK_CUR); // TAG READ 4 BYTE 빼고 SEEK #endif file.Read(&nAudioScale,4); // STREAM_RATE_INDEX = 66 (이미 20 SEEK + 4 BYTE READ 했으니 66-24 = 42 #if (_MSC_VER) file.Seek(STREAM_AUDIO_CHANNEL_INDEX-STREAM_SCALE_INDEX-4,FILE_CURRENT); #else file.Seek(STREAM_AUDIO_CHANNEL_INDEX-STREAM_SCALE_INDEX-4,SEEK_CUR); #endif file.Read(&nAudioChannel,2); // STREAM_SAMPLERATE_INDEX = 68 (= FILE CURSOR) file.Read(&nAudioSampleRate,4); nAudioRate = nAudioSampleRate * nAudioScale; break; case MKTAG('t','x','t','s') : nTxtId = nStreamCount; nStrhPos[nStreamCount++] = nListOffset; break; } } nListOffset += nListSize; } else if(nTagName == MKTAG('s','t','r','f')) { if(bFindVidStream) { #if (_MSC_VER) file.Seek(4,FILE_CURRENT); // 4 BYTE 부터 시작 #else file.Seek(4,SEEK_CUR); // 4 BYTE 부터 시작 #endif file.Read(&nFileWitdh, 4); file.Read(&nFileHeight, 4); bFindVidStream = 0; } nListOffset += nListSize; } else { nListOffset += nListSize; } file.Seek(nListOffset, SEEK_SET); } if(bFindMovi == false) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } dwFileSize -= nListOffset; pData = new unsigned char [dwFileSize]; file.Read(pData, dwFileSize); //file.Close(); // 2018/11/15 fix 적용 nIdxOffset = nListOffset; // 2019/06/13 복구시 시간 확인 #ifdef REPAIR_CHECK_SUBTITLE bool reCoveryFirstTimeCheck = true; #endif i = 0; while(i < dwFileSize) { if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[0])) && (pData[i+2] == 'd') && (pData[i+3] == 'c')) { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if(pData[i+12] == 0x40) { pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; } else { pIdx_info->idx_data[nFrameCount].nFlags = 0x00; } memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0; pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count; // 2018/11/09 FIX 적용 if(nFrameSize % 2) { nFrameSize++; } nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo1Count++; } else { break; } } else if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[1])) && (pData[i+2] == 'd') && (pData[i+3] == 'c')) { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if(pData[i+12] == 0x40) { pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; } else { pIdx_info->idx_data[nFrameCount].nFlags = 0x00; } memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1; pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count; // 2018/11/09 FIX 적용 if(nFrameSize % 2) { nFrameSize++; } nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo2Count++; } else { break; } } else if((pData[i] == '0') && (pData[i+1] == ('0'+nSoundId)) && (pData[i+2] == 'w') && (pData[i+3] == 'b')) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); if(nFrameSize % 2) { nFrameSize++; } pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_AUDIO_0; pIdx_info->frame_list[nFrameCount].nFrame = nAudioCount; // 2018/11/09 FIX 적용 if(nFrameSize % 2) { nFrameSize++; } nIdxOffset += (nFrameSize + 8); nAudioLength += (nFrameSize >> nAudioChannel); i += (nFrameSize + 8); nFrameCount++; nAudioCount++; } else if((pData[i] == '0') && (pData[i+1] == ('0'+nTxtId)) && (pData[i+2] == 't') && (pData[i+3] == 'x')) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); if(nFrameSize % 2) { nFrameSize++; } pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_TEXT_0; pIdx_info->frame_list[nFrameCount].nFrame = nTextLength; // 복구시 자막내 시간 정보와 파일명의 시간 정보가 30분 이상 차이가 발생하는 경우에는 파일 복구 하지 않도록 #ifdef REPAIR_CHECK_SUBTITLE // 2019/06/13 샘플 데이터에서는 512 이상임 && (i+33 < 512)) -> 제거 if(reCoveryFirstTimeCheck) { reCoveryFirstTimeCheck=false; // 30분 이상 차이날 경우 if(RMAVIRepair::compare_subtitle_time(filePath,(char*)&pData[i+8]) == false) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } } #endif // 2018/11/09 FIX 적용 if(nFrameSize % 2) { nFrameSize++; } nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nTextLength++; } else { break; } if(nFrameCount > RECOVERY_MAX_COUNT) { break; } } #if 1 //Frame 정리 if(nFrameCount < 5) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } int nVideo1CountBk = nVideo1Count; int nVideo2CountBk = nVideo2Count; if(nVideo1CountBk) nVideo1CountBk--; if(nVideo2CountBk) nVideo2CountBk--; for(i = (nFrameCount - 1); i > 0 ; i--) { if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_0) { if(pIdx_info->frame_list[i].nFrame == (nVideo1CountBk - 1)) break; if(nVideo1Count) nVideo1Count--; } else if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_1) { if(pIdx_info->frame_list[i].nFrame == (nVideo2CountBk - 1)) break; if(nVideo2Count) nVideo2Count--; } else if(pIdx_info->frame_list[i].nCkID == STREAM_AUDIO_0) { if(nAudioCount) { nAudioLength -= (pIdx_info->idx_data[i].nLength >> nAudioChannel); nAudioCount--; } } else if(pIdx_info->frame_list[i].nCkID == STREAM_TEXT_0) { if(nTextLength) { nTextLength--; } } } nFrameCount = nVideo1Count + nVideo2Count + nAudioCount + nTextLength; #endif // #if 1 //Frame 정리 // SINGLE CH??? //if((nVideo1Count < 5) || (nVideo2Count < 5)) if((nVideo1Count < 5) && (nVideo2Count < 5)) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } pIdx_info->size = nFrameCount * 16; nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8; // 2018/11/09 FIX 적용 -> 2018/11/15 다시 FIX nMoviSize -= (nListOffset - 4); if(nMoviSize % 2) nMoviSize++; nIdxOffset = nListOffset + nMoviSize - 4; nFileSize = pIdx_info->size + nIdxOffset; nMicorSecPerFrmae = 33333; nMaxTransRate = 21170; // 2018/11/15 다시 FIX nMicorSecPerFrmae = 52356; file.Seek(0, SEEK_SET); file.Read(pData, nListOffset); #ifdef MANDO_TB2000 memcpy(pData, stc_pu8Data, _ENCRYPT_SIZE); #endif memcpy(&pData[FILE_SIZE_INDEX], &nFileSize, 4); memcpy(&pData[MAX_TRANSFER_RATE_INDEX], &nMaxTransRate, 4); memcpy(&pData[MICORSECPERFRMAE_INDEX], &nMicorSecPerFrmae, 4); memcpy(&pData[TOTAL_FRAME_INDEX], ((nVideo1Count > nVideo2Count) ? &nVideo1Count : &nVideo1Count), 4); memcpy(&pData[AVIH_FLAG_INDEX], &nAvihFlag, 4); memcpy(&pData[BUFFER_SIZE_INDEX], &nBufferSize, 4); memcpy(&pData[STREAM_COUNT_INDEX], &nStreamCount, 4); memcpy(&pData[VIDEO_WIDTH_INDEX], &nFileWitdh, 4); memcpy(&pData[VIDEO_HEIGHT_INDEX], &nFileHeight, 4); if(nVideoId[0] != (-1)) { if(nStrhPos[nVideoId[0]]) { memcpy(&pData[nStrhPos[nVideoId[0]]+STREAM_LENGTH_INDEX], &nVideo1Count, 4); } } if(nVideoId[1] != (-1)) { if(nStrhPos[nVideoId[1]]) { memcpy(&pData[nStrhPos[nVideoId[1]]+STREAM_LENGTH_INDEX], &nVideo2Count, 4); } } if(nSoundId != (-1)) { if(nStrhPos[nSoundId]) { // 이거 왜하는지 모르겠음 memcpy(&pData[nStrhPos[nSoundId]+STREAM_RATE_INDEX], &nAudioRate, 4); memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioLength, 4); } } if(nTxtId != (-1)) { if(nStrhPos[nTxtId]) { memcpy(&pData[nStrhPos[nTxtId]+STREAM_LENGTH_INDEX], &nTextLength, 4); memcpy(&pData[nStrhPos[nTxtId]+STREAM_TEXT_BUFFER_INDEX], &nTextBufferSize, 4); } } memcpy(&pData[nListOffset-8], &nMoviSize, 4); #ifdef MANDO_TB2000 memcpy(stc_pu8Data, pData, _ENCRYPT_SIZE); efs_file_encrypt(pData, _ENCRYPT_SIZE); #endif file.Seek(0, SEEK_SET); file.Write(pData, nListOffset); delete [] pData; file.Seek(nIdxOffset, SEEK_SET); file.Write(pIdx_info, pIdx_info->size+8); file.Close(); #if (!NO_FILE_RENAME) QFileInfo* fileInfo = new QFileInfo(filePath);// fileInfo(filePath); #if (RM_IS_COMTEC) QString fileName = fileInfo->fileName().replace("_SDEXIT","_Restore",Qt::CaseInsensitive);; #else QString fileName = fileInfo->fileName().replace("_EXIT","_RCVR",Qt::CaseInsensitive);; #endif destPath = fileInfo->absoluteDir().path() + QDir::separator() + fileName; delete fileInfo; RMFileIO::Rename(filePath,destPath); #endif return true; } #endif // #if(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || RM_USE_V50_AVI_REPAIR) // H265 가 아닌 경우 또는 동시 지원일 경우 #if !(H265_SUPPORT || RM_USE_H265_AVI_REPAIR || RM_USE_V50_AVI_REPAIR) || (SUPPORT_AVI_FIX_DURL) bool RMAVIRepair::repair(QString& filePath, QString& destPath) { RMFileIO file = RMFileIO(filePath); if(file.isValid() == false) { return false; } //CFile file; unsigned char *pData = NULL; unsigned int nVideoCount = 0; unsigned int nVideo1Count = 0; unsigned int nVideo2Count = 0; unsigned int nAudioCount = 0; unsigned int nFrameCount = 0; unsigned int nFrameSize = 0; unsigned int nFileSize = 0; unsigned int nIdxOffset = 0; unsigned long i = 0; unsigned int nMoviSize = 0; unsigned int nAudioLength = 0; unsigned int nTextLength = 0; unsigned int nMaxTransRate = 0; unsigned int nAudioRate = 44101;//????? unsigned int nAudioScale = 2; unsigned int nAudioSampleRate = 44100; unsigned int nAudioChannel = 1; _idx1_info_t idx_info, *pIdx_info; unsigned char byTemp[10]; unsigned int nTagName = 0; unsigned int nListSize = 0; unsigned int nListOffset = 0; unsigned int nRatePerScale = 0; unsigned char bFindMovi = false; unsigned int nStrhPos[4] = { 0, 0, 0, 0 }; unsigned int nStreamCount = 0; uint32_t dwFileSize = 0; int nVideoId[2] = { -1, -1 }; int nSoundId = -1; int nTxtId = -1; int nModelNumber = CHIP_A20; #ifdef MANDO_TB2000 efs_file_decrypt(file); if(stc_pu8Data == NULL) { return FALSE; } #endif pIdx_info = &idx_info; memset(pIdx_info, 0x00, sizeof(_idx1_info_t)); memcpy(pIdx_info->szIdx1, "idx1", 4); // if(file.Open(szFilename, CFile::modeReadWrite|CFile::typeBinary, NULL) == false) // return false; dwFileSize = (uint32_t)file.GetLength(); #ifdef MANDO_TB2000 if(memcmp(stc_pu8Data, "RIFF", 4)) { return false; } memcpy(&nFileSize, &stc_pu8Data[4], 4); if(dwFileSize == (nFileSize + 8)) { file.Close(); return true; } #else file.Read(byTemp, 4); if(memcmp(byTemp, "RIFF", 4)) { #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif file.Close(); return false; } file.Read(&nFileSize, 4); if(dwFileSize == (nFileSize + 8)) { file.Close(); return true; } #endif file.Seek(12, SEEK_SET); nListOffset = 12; #ifdef MANDO_TB2000 while(1) { if(nListOffset < _ENCRYPT_SIZE) { memcpy(byTemp, &stc_pu8Data[nListOffset], 8); } else { if(8 != file.Read(byTemp, 8)) break; } #else while(8 == file.Read(byTemp, 8)) { #endif memcpy(&nTagName, &byTemp[0], 4); memcpy(&nListSize, &byTemp[4], 4); nListOffset += 8; if(nTagName == MKTAG('L','I','S','T')) { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nTagName, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nTagName, 4); nListOffset += 4; if (nTagName == MKTAG('m','o','v','i')) { bFindMovi = true; break; } else if (nTagName == MKTAG('h','d','r','l')) { } else if (nTagName == MKTAG('s','t','r','l')) { } else { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nListSize, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nListSize, 4); nListOffset += nListSize; } } else if(nTagName == MKTAG('s','t','r','h')) { #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nTagName, &stc_pu8Data[nListOffset], 4); else #endif file.Read(&nTagName, 4); switch(nTagName) { case MKTAG('v','i','d','s') : if(nVideoId[0] == -1) { unsigned int nVideoScale = 0; unsigned int nVideoRate = 0; file.Seek(16, SEEK_CUR); #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nVideoScale, &stc_pu8Data[nListOffset+4+16], 4); else #endif file.Read(&nVideoScale, 4); #ifdef MANDO_TB2000 if(nListOffset < _ENCRYPT_SIZE) memcpy(&nVideoRate, &stc_pu8Data[nListOffset+4+16+4], 4); else #endif file.Read(&nVideoRate, 4); if(nVideoScale) nRatePerScale = nVideoRate / nVideoScale; nVideoId[0] = nStreamCount; } else { nVideoId[1] = nStreamCount; } nStrhPos[nStreamCount++] = nListOffset; break; case MKTAG('a','u','d','s') : nSoundId = nStreamCount; nStrhPos[nStreamCount++] = nListOffset; if(nModelNumber == CHIP_V35) { file.Seek(62, SEEK_CUR); file.Read(&nAudioChannel, 2); } break; case MKTAG('t','x','t','s') : nTxtId = nStreamCount; nStrhPos[nStreamCount++] = nListOffset; break; } nListOffset += nListSize; } else if(nTagName == MKTAG('s','t','r','d')) { nModelNumber = CHIP_V35; nListOffset += nListSize; } else if(nTagName == MKTAG('a','v','i','h')) { unsigned int avihFlag; file.Seek(12, SEEK_CUR); file.Read(&avihFlag, 4); if(avihFlag == 0x00010010) { nModelNumber = CHIP_V35; } else { nModelNumber = CHIP_A20; } nListOffset += nListSize; } else { nListOffset += nListSize; } file.Seek(nListOffset, SEEK_SET); } if(bFindMovi == false) return false; dwFileSize -= nListOffset; pData = new unsigned char [dwFileSize]; file.Read(pData, dwFileSize); //file.Close(); #ifdef REPAIR_CHECK_SUBTITLE bool reCoveryFirstTimeCheck = true; #endif if(nModelNumber == CHIP_A20) nIdxOffset = nListOffset; else nIdxOffset = 4; i = 0; while(i < dwFileSize) { if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[0])) && (pData[i+2] == 'd') && (pData[i+3] == 'c')) { if(nModelNumber == CHIP_A20) { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if((pData[i+11] == 0x65)||(pData[i+11] == 0x67)) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; else pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0; pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count; nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo1Count++; } else { break; } } else { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if(pData[i+12] == 0x67) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; else pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_0; pIdx_info->frame_list[nFrameCount].nFrame = nVideo1Count; nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo1Count++; } else { break; } } } else if((pData[i] == '0') && (pData[i+1] == ('0'+nVideoId[1])) && (pData[i+2] == 'd') && (pData[i+3] == 'c')) { if(nModelNumber == CHIP_A20) { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if((pData[i+11] == 0x65)||(pData[i+11] == 0x67)) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; else pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1; pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count; nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo2Count++; } else { break; } } else { if((pData[i+8] == 0) && (pData[i+9] == 0) && (pData[i+10] == 0) && (pData[i+11] == 1)) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); if(pData[i+12] == 0x67) pIdx_info->idx_data[nFrameCount].nFlags = AVIIF_KEYFRAME; else pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_VIDEO_1; pIdx_info->frame_list[nFrameCount].nFrame = nVideo2Count; nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nVideo2Count++; } else { break; } } } else if((pData[i] == '0') && (pData[i+1] == ('0'+nSoundId)) && (pData[i+2] == 'w') && (pData[i+3] == 'b')) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_AUDIO_0; pIdx_info->frame_list[nFrameCount].nFrame = nAudioCount; nIdxOffset += (nFrameSize + 8); nAudioLength += (nFrameSize >> nAudioChannel); i += (nFrameSize + 8); nFrameCount++; nAudioCount++; } else if((pData[i] == '0') && (pData[i+1] == ('0'+nTxtId)) && (pData[i+2] == 't') && (pData[i+3] == 'x')) { memcpy(&pIdx_info->idx_data[nFrameCount].nCkID, &pData[i], 4); pIdx_info->idx_data[nFrameCount].nFlags = 0x00; memcpy(&nFrameSize, &pData[i+4], 4); pIdx_info->idx_data[nFrameCount].nLength = nFrameSize; pIdx_info->idx_data[nFrameCount].nOffset = nIdxOffset; pIdx_info->frame_list[nFrameCount].nCkID = STREAM_TEXT_0; pIdx_info->frame_list[nFrameCount].nFrame = nTextLength; // 복구시 자막내 시간 정보와 파일명의 시간 정보가 30분 이상 차이가 발생하는 경우에는 파일 복구 하지 않도록 #ifdef REPAIR_CHECK_SUBTITLE // 2019/06/13 샘플 데이터에서는 512 이상임 && (i+33 < 512)) -> 제거 if(reCoveryFirstTimeCheck) { reCoveryFirstTimeCheck=false; // 30분 이상 차이날 경우 if(RMAVIRepair::compare_subtitle_time(filePath,(char*)&pData[i+8]) == false) { file.Close(); #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif return false; } } #endif nIdxOffset += (nFrameSize + 8); i += (nFrameSize + 8); nFrameCount++; nTextLength++; } else { break; } if(nFrameCount > RECOVERY_MAX_COUNT) break; } #if 0 if(nFrameCount < 5) return false; int nVideo1CountBk = nVideo1Count; int nVideo2CountBk = nVideo2Count; if(nVideo1CountBk) nVideo1CountBk--; if(nVideo2CountBk) nVideo2CountBk--; for(i = (nFrameCount - 1); i > 0 ; i--) { if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_0) { if(pIdx_info->frame_list[i].nFrame == (nVideo1CountBk - 1)) break; if(nVideo1Count) nVideo1Count--; } else if(pIdx_info->frame_list[i].nCkID == STREAM_VIDEO_1) { if(pIdx_info->frame_list[i].nFrame == (nVideo2CountBk - 1)) break; if(nVideo2Count) nVideo2Count--; } else if(pIdx_info->frame_list[i].nCkID == STREAM_AUDIO_0) { if(nAudioCount) { nAudioLength -= (pIdx_info->idx_data[i].nLength >> nAudioChannel); nAudioCount--; } } else if(pIdx_info->frame_list[i].nCkID == STREAM_TEXT_0) { if(nTextLength) nTextLength--; } } nFrameCount = nVideo1Count + nVideo2Count + nAudioCount + nTextLength; #endif #if (USE_2CH_FOLDER) if((nVideo1Count < 5) && (nVideo2Count < 5)) { #if (REPAIR_FAILED_TAG) RMAVIRepair::rename_failed(filePath); #endif file.Close(); return false; } #else if((nVideo1Count < 5) || (nVideo2Count < 5)) return false; #endif pIdx_info->size = nFrameCount * 16; nVideoCount = nVideo1Count + nVideo2Count; file.Seek(0, SEEK_SET); file.Read(pData, nListOffset); #ifdef MANDO_TB2000 memcpy(pData, stc_pu8Data, _ENCRYPT_SIZE); #endif if(nModelNumber == CHIP_A20) nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8 - (nListOffset - 4); else nMoviSize = pIdx_info->idx_data[nFrameCount-1].nLength + pIdx_info->idx_data[nFrameCount-1].nOffset + 8; nIdxOffset = nListOffset + nMoviSize - 4; #if 1 nFileSize = nListOffset + pIdx_info->size + nMoviSize - 4; #else nFileSize = dwFileSize - 8; #endif if(nRatePerScale && nVideo1Count) nMaxTransRate = nMoviSize * nRatePerScale / nVideo1Count; memcpy(&pData[FILE_SIZE_INDEX], &nFileSize, 4); memcpy(&pData[MAX_TRANSFER_RATE_INDEX], &nMaxTransRate, 4); if(nModelNumber == CHIP_A20) memcpy(&pData[TOTAL_FRAME_INDEX], ((nVideo1Count > nVideo2Count) ? &nVideo1Count : &nVideo1Count), 4); else memcpy(&pData[TOTAL_FRAME_INDEX], &nVideoCount, 4); if(nVideoId[0] != (-1)) { if(nStrhPos[nVideoId[0]]) memcpy(&pData[nStrhPos[nVideoId[0]]+STREAM_LENGTH_INDEX], &nVideo1Count, 4); } if(nVideoId[1] != (-1)) { if(nStrhPos[nVideoId[1]]) memcpy(&pData[nStrhPos[nVideoId[1]]+STREAM_LENGTH_INDEX], &nVideo2Count, 4); } if(nSoundId != (-1)) { if(nStrhPos[nSoundId]) { if(nModelNumber == CHIP_A20) { memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioCount, 4); } else { memcpy(&nAudioScale, &pData[nStrhPos[nSoundId]+STREAM_SCALE_INDEX], 4); memcpy(&nAudioSampleRate, &pData[nStrhPos[nSoundId]+STREAM_SAMPLERATE_INDEX], 4); nAudioRate = nAudioSampleRate * nAudioScale; nAudioRate += ((nAudioRate % 1000) / 100); memcpy(&pData[nStrhPos[nSoundId]+STREAM_RATE_INDEX], &nAudioRate, 4); memcpy(&pData[nStrhPos[nSoundId]+STREAM_LENGTH_INDEX], &nAudioLength, 4); } } } if(nTxtId != (-1)) { if(nStrhPos[nTxtId]) memcpy(&pData[nStrhPos[nTxtId]+STREAM_LENGTH_INDEX], &nTextLength, 4); } memcpy(&pData[nListOffset-8], &nMoviSize, 4); #ifdef MANDO_TB2000 memcpy(stc_pu8Data, pData, _ENCRYPT_SIZE); efs_file_encrypt(pData, _ENCRYPT_SIZE); #endif file.Seek(0, SEEK_SET); file.Write(pData, nListOffset); delete [] pData; file.Seek(nIdxOffset, SEEK_SET); file.Write(pIdx_info, pIdx_info->size+8); #if 1 #if (!NO_FILE_RESIZE) file.SetLength(file.GetPosition()); #endif #else { BYTE szTemp[4] = { 'J', 'U', 'N', 'K' }; int nJunkSize = dwFileSize - file.GetPosition() - 8; file.Write(szTemp, 4); file.Write(&nJunkSize, 4); } #endif file.Close(); #if (!NO_FILE_RENAME) destPath = filePath; #if (RM_IS_COMTEC) destPath = RMFileIO::ReplaceFileNameOnly(destPath,"_SDEXIT","_Restore"); //destPath = destPath.replace("_SDEXIT","_Restore",Qt::CaseInsensitive); // 대문자 사용하지 않음 #else destPath = RMFileIO::ReplaceFileNameOnly(destPath,"_EXIT","_RCVR"); // destPath = destPath.replace("_EXIT","_RCVR",Qt::CaseInsensitive); #endif RMFileIO::Rename(filePath,destPath); #endif // TCHAR szOrgName[256]; // _tcscpy(szOrgName, szFilename); // TCHAR *pExit = _tcsstr(szFilename, L"_EXIT"); // if(pExit) // { // #ifdef MANDO_TB2000 // _tcscpy(pExit, L"_RCVR.TBA"); // #else // _tcscpy(pExit, L"_RCVR.AVI"); // #endif // file.Rename(szOrgName, szFilename); // } return true; } #endif // H265 or NOT bool RMAVIRepair::clipToPair(QString& filePath, QString& pairfilePath) { RMFileIO pairfile = RMFileIO(pairfilePath,true); if(pairfile.isValid() == false) { return false; } size_t pairSize = pairfile.GetLength(); size_t copySize = qMin(51200,(int)pairSize); // 전체파일 쓰면 문제 발생함 unsigned char* buffer = (unsigned char*)malloc(copySize); pairfile.Read(buffer,copySize); // 원본에서 읽음 pairfile.Close(); RMFileIO file = RMFileIO(filePath); if(file.isValid() == false) { return false; } file.Write(buffer,copySize); //file.Seek(pairSize,SEEK_SET); #if (!NO_FILE_RESIZE) file.SetLength(pairSize); #endif file.Close(); free(buffer); //탐색기를 open한 상태에서 자동 갱신이 되지 않아서 한번더 writer 해줌. /* RMFileIO reReadFile = RMFileIO(filePath); BYTE* byTemp = (BYTE*)malloc(51200); reReadFile.Read(byTemp, 51200); reReadFile.Close(); RMFileIO reWriteFile = RMFileIO(filePath); reWriteFile.Write(byTemp,51200); reWriteFile.Close(); */ return true; }