Files
fmviewer3/project/fm_viewer/data/rm_avirepair.cpp
2026-02-21 17:11:31 +09:00

1761 lines
50 KiB
C++

#include "rm_avirepair.h"
#include "rm_constants.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#ifdef Q_OS_WIN
#include <windows.h>
#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 <cstdint>
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;
}