#include "rm_video_list.h" #include #include #include #include //#include "rm_uimanager.h" #include "rm_video_item_2ch.h" #include "../ui/rm_dialog_progress.h" //#include "../widgets/rm_toolbutton.h" #include "../core/rm_play_process.h" #include "rm_overwrite.h" #if (DETECT_USB_CHANGE) #include "../core/rm_usb.h" #endif #include #include #if (RM_MODEL == RM_MODEL_TYPE_AN6000) #include "../data/an6000_decode.h" #endif #if (SUPPORT_AVI_FIX_DURL) #include "rm_avirepair.h" #endif #if (PLAYER_ONLY_LIBRARY_MODE) RMVideoFileList* RMVideoFileList::_instance = NULL; #endif // PLAYER_ONLY_LIBRARY_MODE // SORT #if !(USE_1HOUR_FILTER) bool RMVideoItemCompare(RMVideoItem * s1 , RMVideoItem * s2) { // 동일할 경우 상시 먼저 .. if(s1->startTime() == s2->startTime()) { return (int)s1->type < (int)s2->type; } return s1->startTime() < s2->startTime(); } #else // #if !(USE_1HOUR_FILTER) bool RMVideoItemCompare(RMVideoItem * s1 , RMVideoItem * s2) { // 2022/07/12 역순으로 변경 return RMVideoFileList::instance()->bSortDsc ? s2->startTime() < s1->startTime() : s1->startTime() < s2->startTime(); } #endif #if !(USE_1HOUR_FILTER) int RMVideoFileList::n_lastPercent = -1; #if (FILE_FORMAT_MOV && FILE_FORMAT_AVI) QList RMVideoFileList::fileFilters = QList() << QString("*.AVI") << QString("*.MOV") << QString("*.MP4"); #elif (FILE_FORMAT_AVI) QList RMVideoFileList::fileFilters = QList() << QString("*.AVI"); #elif (FILE_FORMAT_MOV) #if (USE_FFMPEG_PW) #if (SUPPORT_MP4TB4) QList RMVideoFileList::fileFilters = QList() << QString("*.TB4") << QString("*.MP4"); #else // SUPPORT_MP4TB4 QList RMVideoFileList::fileFilters = QList() << QString("*.TB4");// << QString("*.MP4"); #endif // SUPPORT_MP4TB4 #else // USE_FFMPEG_PW QList RMVideoFileList::fileFilters = QList() << QString("*.MOV") << QString("*.MP4"); #endif // USE_FFMPEG_PW #endif RMVideoFileList::RMVideoFileList(QObject* parent) : QObject(parent) { _filter = FILTER_NORMAL | FILTER_EVENT; _playItem = NULL; #if (USE_1HOUR_FILTER) b1HourList = true; // 1시간 단위 리스트 bSortDsc = true; // (기본값) 표시=최신순으로 정렬, 시간순으로 정렬 #endif // USE_1HOUR_FILTER #if (SUPPORT_LOADING_CANCEL) bCancelLoading = false; // 로딩 취소 #endif } // 모델별 채널 처리 #if !(RECURSIVE_APPEND_FILE) void RMVideoFileList::_appendFrontRear(QString& folder,QList& list) { // 신규 모델 처리시 ELSE 를 사용하지 않는다 #if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22) const QList folders = QList() << "F" << "R"; #elif (RM_MODEL == RM_MODEL_TYPE_ADT_CAPS) const QList folders = QList() << "1" << "2"; #endif foreach (QString each_folder, folders) { QString current_front = QDir::cleanPath(folder + PATH_COMPONENT + each_folder); if(QFile::exists(current_front)) { QDir fdir(current_front); fdir.setNameFilters(RMVideoFileList::fileFilters); // 확장자 필터 QStringList allFiles = fdir.entryList(); foreach (const QString &str, allFiles) { if(str == "." || str == "..") { continue; } QDateTime dateTime; QString filePath = QDir::cleanPath(current_front + PATH_COMPONENT + str); // static 이라 일단 중복되어도 추가함. if( RMVideoItem::IsFeasible(filePath,&dateTime) != (int)TYPE_UNDEFINED) { list.append(QUrl::fromLocalFile(filePath)); } } } } } #endif // #if !(RECURSIVE_APPEND_FILE) #if (RM_MODEL == RM_MODEL_TYPE_AN6000) void RMVideoFileList::removeTemps() { for(int i=0;i<_items.size();i++){ _items.at(i)->removeTemp(); } } #endif // bool RMVideoFileList::addItem(QString filePath,QDateTime* pDateTime,GROUP_TYPE type) { QString cleanPath = QDir::cleanPath(filePath); #if (TRI_CHANNEL || PENTA_CHANNEL) int ch = 1; RMVideoFileList::_checkChannelInfo(filePath,&ch); #else // TRI_CHANNEL #if (FORCE_2CH || SINGLE_CH_VIEWER) bool isCH2 = false; #else // !FORCE_2CH bool isCH2 = false; #if (SUPPORT_2CH) bool is2CH = false; // 1FILE 2CH 영상 RMVideoFileList::_checkChannelInfo(filePath,&isCH2,&is2CH); #else // SUPPORT_2CH RMVideoFileList::_checkChannelInfo(filePath,&isCH2); #endif // SUPPORT_2CH #endif // FORCE_2CH #endif // TRI_CHANNEL // 무조건 중복체크 해야함 if(itemExist(cleanPath) == true) { //qInfo() << "exist skip:" << cleanPath << __FUNCTION__; return false; } #if (SUPPORT_AVI_FIX_DURL) // 복구 필요 if(cleanPath.endsWith("_EXIT.AVI",Qt::CaseInsensitive)) { QString destPath; if (RMAVIRepair::repairV50(filePath,destPath) == true) { if(destPath.isEmpty() == false) // true 일 경우 복구할 필요 없음 { cleanPath = destPath; } } else { return false; } } #endif #if (TRI_CHANNEL || PENTA_CHANNEL) RMVideoItem* item = new RMVideoItem(cleanPath,ch,pDateTime); #else RMVideoItem* item = new RMVideoItem(cleanPath,isCH2,pDateTime); #endif if(item->isValid() == true) { item->type = type; item->dropItem = true; // 전방, 또는 후방 파일 확인해서 추가 #if !(FORCE_2CH || SINGLE_CH_VIEWER) if(_addOtherChannelFile(item)) { #if (CHECK_REAR_DURATION) // 후방도 재생시간 확인하여 제거 if(item->isRearDuration() == false) { delete item; item = NULL; } #endif // CHECK_REAR_DURATION } #endif // FORCE_2CH #if (CHECK_VIDEO_BITRATE) item->testBitrate2CH(); // 후방 파일만 존재하는 경우 후방 파일의 bitrate 가 < 미만일 경우 if(item->anyFilePath().length() == 0) { delete item; item = NULL; } #endif #if (SUPPORT_2CH) if(is2CH) { item->filePathCH2 = item->filePath; } #endif // SUPPORT_2CH if(item != NULL) { _items.append(item); } } else { delete item; return false; } return true; } void RMVideoFileList::checkedItems(QList& items) { foreach (RMVideoItem* item, filteredItems()) { #if (SINGLE_SAVE_CHECK_FILE) if(item->checked) { // 선택된 파일이 존재할 경우 1개만 리턴 items.append(item); return; } #else // SINGLE_SAVE_CHECK_FILE #if (SINGLE_SAVE_FILE) if(item == _playItem) { items.append(item); } #else if(item->checked) { items.append(item); } #endif #endif // SINGLE_SAVE_CHECK_FILE } #if (SINGLE_SAVE_CHECK_FILE) // 선택된 파일이 없을 경우 재생중인 foreach (RMVideoItem* item, filteredItems()) { if(item == _playItem) { item->checked = true; items.append(item); } } #endif // SINGLE_SAVE_CHECK_FILE } RMVideoItem* RMVideoFileList::searchPlayItem(QString prefix) { foreach (RMVideoItem* item, filteredItems()) { //qInfo() << item->fileName << prefix << __FUNCTION__; if(item->fileName.startsWith(prefix)) { return item; } } return NULL; } void RMVideoFileList::_backupOverwrite(QString target,QString src,int countLeft) { bool bCopy = true; if(QFile::exists(target)) { // 확인 처리 해야할 경우 if (RMOverwrite::check(OVERWRITE_OPTION_ASK)) { QFileInfo info(target); QString baseName = info.baseName(); #if (0) // 파일 인덱스 존재할 경우 제거 // NNF_191125-092637-003801_2 QStringList ls = baseName.split("-",QString::SkipEmptyParts); if(ls.length() == 3) { ls.removeLast(); } baseName = ls.join("-"); #endif // RMOverwrite::currentFileName = baseName + "." + info.suffix(); RMOverwrite::currentCount = countLeft; emit backupPaused(true); RMOverwrite::lock(); RMOverwrite::wait(); RMOverwrite::unlock(); emit backupPaused(false); // 작업 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { return; } } // 확인 처리 후.. if (RMOverwrite::check(OVERWRITE_OPTION_SKIP)) { bCopy = false; } else if (RMOverwrite::check(OVERWRITE_OPTION_WRITE)) { bCopy = true; //qInfo() << "remove:" << target; QFile::remove(target); } // // 전체가 아닐 경우 다시 ASK 로 변경 // if(RMOverwrite::check(OVERWRITE_OPTION_ALL) == false) { // RMOverwrite::gCurrent = OVERWRITE_OPTION_ASK; // } } if(bCopy) { QFile::copy(src,target); #if (RM_MODEL == RM_MODEL_TYPE_AN6000) // 디코딩 if(is_encrypted_an6000(target.toStdWString().c_str())) { decrypt_an6000(target.toStdWString().c_str()); } #endif // } } void RMVideoFileList::backup(QString dest) { QList items; checkedItems(items); if(items.isEmpty()){ return; } RMOverwrite::reset(); // 초기화 emit backupStarted(); QCoreApplication::processEvents(); QThread::msleep(1); RMVideoFileList::n_lastPercent = -1; int index = 0; int count = items.count(); //qInfo() << __FUNCTION__; foreach (RMVideoItem* item, items) { #if (SINGLE_SAVE_FILE && !SINGLE_SAVE_CHECK_FILE) if(item != _playItem) { continue; } qInfo() << __FUNCTION__ << item->anyFilePath(); #else if(item->checked == false) { continue; } #endif if(item->filePath.isEmpty() == false) { QFileInfo info(item->filePath); QString target = QDir::cleanPath(dest + QDir::separator() + info.baseName() + "." + info.suffix()); _backupOverwrite(target,item->filePath,items.count() - index); // 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { break; } } #if !(DUAL_CH_FILE || SINGLE_CH_VIEWER) if(item->filePathCH2.isEmpty() == false) { QFileInfo info(item->filePathCH2); QString target = QDir::cleanPath(dest + QDir::separator() + info.baseName() + "." + info.suffix()).toUpper(); _backupOverwrite(target,item->filePathCH2,items.count() - index); // 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { break; } } #endif #if (PENTA_CHANNEL) if(item->filePathCH3.isEmpty() == false) { QFileInfo info(item->filePathCH3); QString target = QDir::cleanPath(dest + QDir::separator() + info.baseName() + "." + info.suffix()).toUpper(); _backupOverwrite(target,item->filePathCH3,items.count() - index); // 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { break; } } if(item->filePathCH4.isEmpty() == false) { QFileInfo info(item->filePathCH4); QString target = QDir::cleanPath(dest + QDir::separator() + info.baseName() + "." + info.suffix()).toUpper(); _backupOverwrite(target,item->filePathCH4,items.count() - index); // 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { break; } } if(item->filePathCH5.isEmpty() == false) { QFileInfo info(item->filePathCH5); QString target = QDir::cleanPath(dest + QDir::separator() + info.baseName() + "." + info.suffix()).toUpper(); _backupOverwrite(target,item->filePathCH5,items.count() - index); // 취소 if(RMOverwrite::check(OVERWRITE_OPTION_CANCEL)) { break; } } #endif // PENTA_CHANNEL // 중복 처리 선택 옵션에서 전체가 아닐 경우 다시 ASK 로 변경 if(RMOverwrite::check(OVERWRITE_OPTION_ALL) == false) { RMOverwrite::gCurrent = OVERWRITE_OPTION_ASK; } int percent = (int)(((double)++index) / ((double)count) * (double)(PROGRESS_BAR_MAX)); LOG_INFO << "backup:" << item->anyFilePath() << " percent:" << percent; if(percent != RMVideoFileList::n_lastPercent) { RMVideoFileList::n_lastPercent = percent; emit updateProgress(percent); QCoreApplication::processEvents(); QThread::usleep(1); // unsigned long nSleep = (RMVideoFileList::n_lastPercent == -1) ? 100 : 5; } } emit backupEnd(); } //! \brief 리스트 삭제하고 이벤트 전달 void RMVideoFileList::clearList() { emit listUpdateStarted(true); #if (RM_MODEL == RM_MODEL_TYPE_TBD360 || RM_MODEL_EMT_KR) // RM_MODEL == RM_MODEL_TYPE_XLDR_88 || _filter = FILTER_NORMAL; #else // RM_MODEL_TYPE_TBD360 _filter = FILTER_ALL; #endif // RM_MODEL_TYPE_TBD360 _items.clear(); QCoreApplication::processEvents(); #if (USE_1HOUR_FILTER) set1HourList(b1HourList,false,NULL); // 정렬에 따른 1시간 필터 처리 #else // USE_1HOUR_FILTER // _filtered Item 처리 _updateItemsByFilter(); #endif // #if (USE_1HOUR_FILTER) #if (USE_1HOUR_FILTER) count1HourItems(); #endif QCoreApplication::processEvents(); QThread::usleep(1); emit listUpdateEnd(true,NULL); emit loadListEnd(); } void RMVideoFileList::loadFromList(QList list,bool bPlayFirstAdded) { Q_UNUSED(bPlayFirstAdded) emit listUpdateStarted(true); #if (SUPPORT_LOADING_CANCEL) bCancelLoading = false; #endif // #if (SUPPORT_LOADING_CANCEL) if(list.isEmpty()) { #if (USE_1HOUR_FILTER) count1HourItems(); #endif emit listUpdateEnd(true,NULL); return; } #if (RM_MODEL == RM_MODEL_TYPE_TBD360 || RM_MODEL_EMT_KR) // RM_MODEL_EMT_KR = 실제로는 maxType 선택됨 _filter = FILTER_NORMAL; #else // RM_MODEL_TYPE_TBD360 _filter = FILTER_ALL; #endif // RM_MODEL_TYPE_TBD360 _items.clear(); QCoreApplication::processEvents(); RMVideoFileList::n_lastPercent = -1; int index = 0; int count = list.count(); #if (DETECT_USB_CHANGE) // 경로가 USB 일 경우 드라이버 지정 QString path = list.first().toLocalFile(); RMApp::instance()->usb->setOpenDriveWithPath(path); //((WindowMain*)RMApp::instance()->pMainWindow)->_usb->setOpenDriveWithFolder(); #endif // DETECT_USB_CHANGE foreach (const QUrl &url, list) { int percent = (int)(((double)++index) / ((double)count) * (double)(PROGRESS_BAR_MAX)); if(percent % 2 == 0 && percent != RMVideoFileList::n_lastPercent) { RMVideoFileList::n_lastPercent = percent; emit updateProgress(percent); // SLEEP 기능 제거하면 썸네일 표시안됨??? //QThread::usleep(1); //QCoreApplication::processEvents(); } QString fileName = url.toLocalFile(); QDateTime dateTime; RMVideoFileList::GROUP_TYPE type = ( RMVideoFileList::GROUP_TYPE)RMVideoItem::IsFeasible(fileName,&dateTime); if(type == RMVideoFileList::TYPE_UNDEFINED) { continue; } if(addItem(fileName,&dateTime,type) == true) // 경로에 / \ 가 동시에 들어가면 안됨.. { } #if (SUPPORT_LOADING_CANCEL) if(bCancelLoading) { break; } #endif // #if (SUPPORT_LOADING_CANCEL) } #if (USE_1HOUR_FILTER) setSortList(bSortDsc); // 정렬처리 set1HourList(b1HourList,false,NULL); // 정렬에 따른 1시간 필터 처리 #else // USE_1HOUR_FILTER qSort(_items.begin(),_items.end(),RMVideoItemCompare); #if (RM_MODEL_EMT_KR) // 로딩된 파일 중 가장 많은 파일이 존재하는 녹화타입 선택 selectMaxCountFilter(); #endif // RM_MODEL_EMT_KR // _filtered Item 처리 _updateItemsByFilter(); #endif // #if (USE_1HOUR_FILTER) #if (USE_1HOUR_FILTER) count1HourItems(); #endif QCoreApplication::processEvents(); QThread::usleep(1); emit listUpdateEnd(true,NULL); #if (PLAY_FIRST_LOADED) int old = getPlayIndex(); // TELEBIT 는 간편/전체 리스트 검색 (현재 리스트와 동일하지 않을 수 있음) if(_filteredItems.count() > 0) { emit playItemFound(_filteredItems.first(),old); } #endif emit loadListEnd(); } #if (RM_MODEL_EMT_KR) int RMVideoFileList::currentFilterIndex() { QList filters = QList() << FILTER_NORMAL << FILTER_EVENT << FILTER_PARK << FILTER_PARK_EVENT << FILTER_MANUAL << FILTER_MYBOX; for(int i=0;itype == RMVideoFileList::TYPE_UNDEFINED) { continue; } filterCount[item->type] += 1; } int maxType = 0; int maxCount = 0; for(int i=0;i<10;i++) { if(filterCount[i] > maxCount) { maxCount = filterCount[i]; maxType = i; } } _filter = filterTypeFromGroupType((GROUP_TYPE)maxType); //qInfo() << "MAX TYPE:" << _filter << __FUNCTION__; } #endif // RM_MODEL_EMT_KR #ifdef _DEBUG void RMVideoFileList::print() { foreach (RMVideoItem* item, _items) { item->print(); } } #endif RMVideoFileList::GROUP_TYPE RMVideoFileList::checkGroupTypeFromFolderPath(QString folderPath) { QStringList parts = folderPath.split(PATH_COMPONENT); QString name = parts.last(); name = name.toUpper(); // 모델은 폴더만으로 파일 종류 구분 불가 if(name.contains("Event",Qt::CaseInsensitive) == true) { return TYPE_EVENT; } else if(name.contains("Normal",Qt::CaseInsensitive) == true) // 상시 { return TYPE_NORMAL; } return TYPE_UNDEFINED; } bool RMVideoFileList::isRootPath(QString folderPath) { QDir dir(folderPath); dir.setFilter(QDir::Dirs); QStringList allDirs = dir.entryList(); foreach (const QString &str, allDirs) { if(str == "." || str == "..") { continue; } QString eachFolderPath = folderPath + PATH_COMPONENT + str; if(RMVideoFileList::checkGroupTypeFromFolderPath(eachFolderPath) != RMVideoFileList::TYPE_UNDEFINED) { return true; } } return false; } #if (RECURSIVE_APPEND_FILE) void RMVideoFileList::appendFolderToList(QString folderPath,QList& list,int depth) { if(RECURSIVE_FOLDER_MAX_DEPTH > depth) { QDir dir(folderPath); dir.setFilter(QDir::Dirs); foreach (const QString& eachFolder, dir.entryList()) { if(eachFolder == "." || eachFolder == "..") { continue; } // 폴더는 탐색 QString fullPath = QDir::cleanPath(folderPath + PATH_COMPONENT + eachFolder); RMVideoFileList::appendFolderToList(fullPath,list,depth+1); } } else { //qInfo() << "SKIP:" << folderPath; } QDir dirFile(folderPath); dirFile.setNameFilters(RMVideoFileList::fileFilters); QStringList allFiles = dirFile.entryList(); foreach (const QString& eachFile, allFiles) { QDateTime dateTime; QString fullPath = QDir::cleanPath(folderPath + PATH_COMPONENT + eachFile); // static 이라 일단 중복되어도 추가함. if( RMVideoItem::IsFeasible(fullPath,&dateTime) != (int)TYPE_UNDEFINED) { list.append(QUrl::fromLocalFile(fullPath)); } } } #else void RMVideoFileList::appendToList(QString folderPath,QList& list, bool baseFolderOnly) { if(baseFolderOnly == true) { RMVideoFileList::GROUP_TYPE type = RMVideoFileList::checkGroupTypeFromFolderPath(folderPath); if(type == TYPE_UNDEFINED) { return; } } QDir dir(folderPath); dir.setNameFilters(RMVideoFileList::fileFilters); QStringList allFiles = dir.entryList(); foreach (const QString &str, allFiles) { QDateTime dateTime; QString filePath = QDir::cleanPath(folderPath + PATH_COMPONENT + str); // static 이라 일단 중복되어도 추가함. if( RMVideoItem::IsFeasible(filePath,&dateTime) != (int)TYPE_UNDEFINED) { list.append(QUrl::fromLocalFile(filePath)); } else { //qInfo() << "NO FEASIBLE" << filePath; } } // Front, Rear 폴더 탐색 _appendFrontRear(folderPath,list); } void RMVideoFileList::appendFolderToList(QString rootFolderPath,QList& list) { QDir dir(rootFolderPath); dir.setFilter(QDir::Dirs); QStringList allDirs = dir.entryList(); // 자체 폴더도 추가 RMVideoFileList::appendToList(rootFolderPath,list,false); foreach (const QString &str, allDirs) { if(str == "." || str == "..") { continue; } QString eachFolderPath = QDir::cleanPath(rootFolderPath + PATH_COMPONENT + str); //qInfo() << "appendToList check:" << eachFolderPath; if(RMVideoFileList::checkGroupTypeFromFolderPath(eachFolderPath) != RMVideoFileList::TYPE_UNDEFINED) { //qInfo() << "appendToList" << eachFolderPath; RMVideoFileList::appendToList(eachFolderPath,list,true); // root 에서 처리하면 기본 폴더만 추가 } // 채널 폴더 (EVENT 등 폴더 내부에서 열기) else if (str == QString("1") || str == QString("2")) { RMVideoFileList::appendToList(eachFolderPath,list,false); } } } #endif bool RMVideoFileList::_searchItem(bool next, RMVideoItem** item,int fromIndex) { *item = NULL; if(fromIndex == -1 && _playItem == NULL) { return false; } QList& items = filteredItems(); int offset = next ? 1 : -1; // next, previous int index = fromIndex == -1 ? (items.indexOf(_playItem) + offset) : (fromIndex + offset); #if (RM_MODEL_EMT_KR) if(index < -1) { #else if(index < 0) { #endif return false; } else if (next == true && index >= items.count()) { #if (PROFILE_VIDEO_FILE_LOADING) LOG_VLOAD << "VIDEO LIST PLAY PROFILE DONE" << LOG_VLOAD_T2; // 1회만 반복함 return false; #endif index = 0; } #if (RM_MODEL_EMT_KR) else if (index < 0) { index = items.size() - 1; } #endif *item = items.at(index); return true; } RMVideoItem* RMVideoFileList::nexItem(bool bNext) { RMVideoItem* item = NULL; if(_playItem != NULL && _searchItem(bNext,&item,getPlayIndex())) { return item; } return NULL; } bool RMVideoFileList::isNextPlayItemExist(bool bNext) { if(_playItem == NULL) { return false; } RMVideoItem* item = NULL; return _searchItem(bNext,&item,getPlayIndex()); } RMVideoItem* RMVideoFileList::itemWithPath(QString filePath) { #if (FORCE_2CH || SINGLE_CH_VIEWER) QString search = QFileInfo(filePath).baseName(); #else QString search = RMVideoItem::fileNameWithoutChannel(filePath); #endif foreach (RMVideoItem* item, _items) { #if (FORCE_2CH || SINGLE_CH_VIEWER) QString compare = QFileInfo(item->anyFilePath()).baseName(); #else QString compare = RMVideoItem::fileNameWithoutChannel(item->anyFilePath()); #endif if(search.compare(compare,Qt::CaseInsensitive) == 0) { return item; } } return NULL; } void RMVideoFileList::playItem(RMVideoItem* item) { if(item != NULL) { int old = getPlayIndex(); emit playItemFound(item,old); } } void RMVideoFileList::onPlayNextVideo(int fromIndex) { #if (FFMPEG_VTHREAD_DEBUG) emit playNoMoreItem(); // 더이상 플레이할 아이템 없음 return; #endif // 연속재생 방지 //qInfo() << "onPlayNextVideo:" << fromIndex; if((fromIndex == -1 && _playItem == NULL) || RMPlayProcess::bProcessing) { return; } int old = getPlayIndex(); //qInfo() << "onPlayNextVideo old index:" << old; RMVideoItem* item = NULL; if(_searchItem(true,&item,fromIndex) == true) // 탐색 { emit playItemFound(item,old); // 탐색완료 -> 다음파일 } else { emit playNoMoreItem(); // 더이상 플레이할 아이템 없음 } } void RMVideoFileList::onPlayPreviousVideo(int fromIndex) { if((fromIndex == -1 && _playItem == NULL) || RMPlayProcess::bProcessing) { return; } int old = getPlayIndex(); RMVideoItem* item = NULL; if(_searchItem(false,&item,fromIndex) == true) // 탐색 { emit playItemFound(item,old); // 탐색완료 } else { emit playNoMoreItem(); // 더이상 플레이할 아이템 없음 } } #if (USE_DATE_TIME_LIST) QDate RMVideoFileList::getFirstDate() { if(_items.isEmpty()) { return QDate(); } return _items.first()->startTime().date(); } void RMVideoFileList::getMonthList(int year, int month, QSet& ret, QList& dayItems) { dayItems.clear(); ret.clear(); // 이전달 마지막일 QDate after = QDate(year,month,1).addDays(-1); // 다음달 1일 QDate before = QDate(year,month,1).addMonths(1); for(int i=0;i<_items.size();i++) { QDate st = _items.at(i)->startTime().date(); if(st > after && st < before) { dayItems.append(_items.at(i)); // 해당일자 아이템 추가 ret.insert(st.day()); // 날짜 추가 } } } #endif// USE_DATE_TIME_LIST int RMVideoFileList::removeItem(RMVideoItem* item) { // 필터된 아이템의 인덱스를 리턴한다 int index = _filteredItems.indexOf(item); _filteredItems.removeAt(index); // 전체 아이템에서도 제거 _items.removeOne(item); return index; } #if (USE_1HOUR_FILTER) RMVideoItem* RMVideoFileList::findFirstItemIn1Hour(RMVideoItem* searchItem) { if(searchItem == NULL) { return NULL; } // 최신순으로 표시할 경우 // QDateTime fromDateTime = simpleFromDateTime(searchItem->startTime()); foreach (RMVideoItem* item, _items) { if(bSortDsc) { int secsTo = item->startTime().secsTo(fromDateTime); if (secsTo > 0 && secsTo < 3600) { return item; } } else { if (item->startTime().secsTo(fromDateTime) <= 0 ) { return item; } } } return NULL; // 발생할 수 없음.. } QDateTime RMVideoFileList::simpleFromDateTime(QDateTime& startTime) { int hour = startTime.time().hour(); int perHour = 1;//3600 / 3600; if(perHour != 1) { hour = hour - (hour % perHour); } return bSortDsc ? QDateTime(startTime.date(),QTime(hour,0,0)).addSecs(3600) : QDateTime(startTime.date(),QTime(hour,0,0)); } QDateTime RMVideoFileList::simpleFromDateTime2(QDateTime& startTime) { int hour = startTime.time().hour(); int perHour = 1;//3600 / 3600; if(perHour != 1) { hour = hour - (hour % perHour); } return (!bSortDsc) ? QDateTime(startTime.date(),QTime(hour,0,0)).addSecs(3600) : QDateTime(startTime.date(),QTime(hour,0,0)); } void RMVideoFileList::load1HourList(QList& res) { res.clear(); // N 시간 단위로 파일 추가 QDateTime lastDateTime = QDateTime(); foreach (RMVideoItem* item, _items) { item->checked = false; QDateTime currentTime = item->startTime(); if(bSortDsc) { if(lastDateTime.isValid() == true && -lastDateTime.secsTo(currentTime) < 3600 ) { continue; } } else { if(lastDateTime.isValid() == true && lastDateTime.secsTo(currentTime) < 3600 ) { continue; } } res.append(item); lastDateTime = simpleFromDateTime(item->startTime()); } } void RMVideoFileList::load1HourInList(QDateTime dt, QList& res) { res.clear(); QDateTime fromDateTime = simpleFromDateTime(dt); foreach (RMVideoItem* item, _items) { qint64 diff = fromDateTime.secsTo(item->startTime()); if(bSortDsc) { diff *= -1; } if(diff >= 0 && diff < 3600) { res.append(item); } } } QPair RMVideoFileList::getThumbnailPath(RMVideoItem* item) { // C:\stroage\testing\TELEBIT\20231116_TB4000_SD3\Video\2023_11\15\17\20231115-172447_PSR0_0000.tb4 // C:\stroage\testing\TELEBIT\20231116_TB4000_SD3\Photo\2023_11\15\17\20231115-172447_PSR0_0000_0.jpg // C:\stroage\testing\TELEBIT\20231116_TB4000_SD3\Photo\2023_11\15\17\20231115-172447_PSR0_0000_1.jpg QString src = item->filePath; if(QFile::exists(item->filePath)){ int idx = src.lastIndexOf("Video"); if(idx >= 0) { QString base = src.replace(idx,5,"Photo"); QString f = base; f.replace(".tb4","_0.jpg"); if(!QFile::exists(f)) { f = ""; } QString s = base; s.replace(".tb4","_1.jpg"); if(!QFile::exists(s)) { s = ""; } return QPair(f,s); } } return QPair("",""); } void RMVideoFileList::loadThumbnails(QList& src, QList>& res) { res.clear(); // Thumbnail 과 동기화를 위해 존재하지 않는 아이템은 제거 QList removes = QList(); foreach (RMVideoItem* item, src) { QPair paths = getThumbnailPath(item); if(paths.first.isEmpty() && paths.second.isEmpty()) { // removes.append(item); // 제거하지 않고 NO_THUMBNAIL 추가 // continue; // 문제는 NO IMAGE 로는 이미지 선택시 재생할 수 없음.. QString name = QFileInfo(item->filePath).baseName(); paths = QPair(name+"_0",name+"_1"); // ":/image/no_thumbnail.png",":/image/no_thumbnail.png" } res.append(paths); } // Thumbnail 과 동기화를 위해 존재하지 않는 아이템은 제거 //foreach (RMVideoItem* item, removes) //{ // src.removeOne(item); //} } void RMVideoFileList::count1HourItems() { count1Hour = 0; // N 시간 단위로 파일 추가 QDateTime lastDateTime = QDateTime(); foreach (RMVideoItem* item, _items) { QDateTime currentTime = item->startTime(); if(bSortDsc) { if(lastDateTime.isValid() == true && -lastDateTime.secsTo(currentTime) < 3600 ) { continue; } } else { if(lastDateTime.isValid() == true && lastDateTime.secsTo(currentTime) < 3600 ) { continue; } } count1Hour++; lastDateTime = simpleFromDateTime(item->startTime()); } } void RMVideoFileList::set1HourList(bool b1Hour, bool bEmit, RMVideoItem* selected) { if(bEmit) { emit listUpdateStarted(false); } _filteredItems.clear(); b1HourList = b1Hour; if(b1HourList) { load1HourList(_filteredItems); } else { foreach (RMVideoItem* item, _items) { item->checked = false; _filteredItems.append(item); } } // N 시간 단위로 파일 추가 // QDateTime lastDateTime = QDateTime(); // foreach (RMVideoItem* item, _items) { // if(b1Hour) { // QDateTime currentTime = item->startTime(); // if(bSortDsc) { // if(lastDateTime.isValid() == true && -lastDateTime.secsTo(currentTime) < 3600 ) { // continue; // } // } // else { // if(lastDateTime.isValid() == true && lastDateTime.secsTo(currentTime) < 3600 ) { // continue; // } // } // } // item->checked = false; // _filteredItems.append(item); // if(b1Hour) { // lastDateTime = simpleFromDateTime(item->startTime()); // } // } setPlayItem(NULL); if(bEmit) { emit listUpdateEnd(false,findFirstItemIn1Hour(selected)); } } void RMVideoFileList::setSortList(bool bDsc) { bSortDsc = bDsc; qSort(_items.begin(),_items.end(),RMVideoItemCompare); } #endif // #if (USE_1HOUR_FILTER) /* bool RMVideoFileList::_updateChannel(QString filePath,bool isCH2) { QString srcName = _checkChannelInfo(filePath,NULL); foreach (RMVideoItem* item, _items) { QString destPath = isCH2 ? item->filePath : item->filePathCH2; bool destIsCH2 = false; QString destName = _checkChannelInfo(destPath,&destIsCH2); if(srcName.compare(destName,Qt::CaseInsensitive) == 0 && isCH2 != destIsCH2) { if (isCH2 == true) { item->filePathCH2 = filePath; } else { item->filePath = filePath; } return true; } } return false; } */ #if !(USE_1HOUR_FILTER) void RMVideoFileList::setFilterSingle(RMVideoFileList::FILTER filter) { _filter = filter; _updateItemsByFilter(); } void RMVideoFileList::setFilter(RMVideoFileList::FILTER filter, bool on) { if(on){ _filter = _filter | filter; } else { _filter = _filter & ~filter; } _updateItemsByFilter(); } void RMVideoFileList::clearChecked() { foreach (RMVideoItem* item, _items) { item->checked = false; } } void RMVideoFileList::_updateItemsByFilter() { emit listUpdateStarted(false); _filteredItems.clear(); foreach (RMVideoItem* item, _items) { // 전방이 없을 경우 강제 전방 표시 // Player 의 Rearswap 사용 // if(item->isSingleChannel() && item->filePath.isEmpty()) { // item->filePath = item->filePathCH2; // item->filePathCH2 = ""; // item->forceSwap = true; // } else { // item->forceSwap = false; // } item->checked = false; RMVideoFileList::FILTER filter = filterTypeFromGroupType(item->type); if(checkFilter(filter)) { _filteredItems.append(item); } } setPlayItem(NULL); emit listUpdateEnd(false,NULL); } #endif // #if !(USE_1HOUR_FILTER) // 모델별로 채널 확인해서 처리해야 하는 기능 bool RMVideoFileList::itemExist(QString filePath) { #if (RM_MODEL_EMT_KR) QString search = filePath; #else // RM_MODEL_EMT_KR #if (FORCE_2CH || SINGLE_CH_VIEWER) QString search = QFileInfo(filePath).baseName(); #else // FORCE_2CH QString search = RMVideoItem::fileNameWithoutChannel(filePath); #endif // FORCE_2CH #endif // !RM_MODEL_EMT_KR foreach (RMVideoItem* item, _items) { #if (RM_MODEL_EMT_KR) // MYBOX 가 존재하니 단순 경로만 비교 if(search.compare(item->filePath,Qt::CaseInsensitive) == 0) { return true; } #else // RM_MODEL_EMT_KR #if (FORCE_2CH || SINGLE_CH_VIEWER) QString compare = QFileInfo(item->anyFilePath()).baseName(); #else QString compare = RMVideoItem::fileNameWithoutChannel(item->anyFilePath()); #endif if(search.compare(compare,Qt::CaseInsensitive) == 0) { return true; } #endif // !RM_MODEL_EMT_KR } return false;//_updateChannel(filePath,isCH2); } // 멀티파일(채널) 포멧 확인하고 날짜제외 제거하고 리턴 #if (RM_MODEL == RM_MODEL_TYPE_NX_DRW22) QString RMVideoFileList::_checkChannelInfo(QString filePath,bool *isCH2) { QString baseName = QFileInfo(filePath).baseName(); if(isCH2 != NULL) { *isCH2 = baseName.endsWith("R",Qt::CaseInsensitive); } // 동일한 영상/전후방 비교용으로만 사용됨 baseName.truncate(baseName.length()-1); return baseName; } // 전방 또는 후방 파일 확인해서 추가 bool RMVideoFileList::_addOtherChannelFile(RMVideoItem *item) { QString filePath = item->anyFilePath(); QString fileFolder = QFileInfo(filePath).absolutePath(); bool isCH2 = false; QString searchFileName; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&isCH2); // 탐색할 파일명 searchFileName = baseName + (isCH2 ? "F.mov" : "R.mov"); QStringList searchPaths = QStringList() << QDir::cleanPath((fileFolder + QDir::separator() + searchFileName)); // 폴더의 폴더 QString fileFolderFolder = QFileInfo(fileFolder).baseName(); if(fileFolderFolder == "F" || fileFolderFolder == "R") { QString searchFolder = (fileFolderFolder == "F" ? "R" : "F"); searchPaths << (QDir::cleanPath(QFileInfo(fileFolder).absolutePath() + QDir::separator() + searchFolder + QDir::separator() + searchFileName)); } // 탐색폴더 확인 foreach (QString path, searchPaths) { if( QFile::exists(path) ) { if(isCH2) { item->filePath = path; } else { item->filePathCH2 = path; } return true; } } return false; } QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); // FILE200713-101324-000001F.MOV // EMER200713-101525-000003F.MOV QRegExp regexp("^[F,E][I,M][L,E][E,R][0-9]{6}-[0-9]{6}-[0-9]{6}[F,R]"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } if(baseName.startsWith("F")) { *type = TYPE_NORMAL; } else { *type = TYPE_EVENT; } return baseName.mid(4,13); } #elif (RM_MODEL == RM_MODEL_TYPE_MH9000) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString baseName = QFileInfo(QDir::cleanPath(filePath)).baseName(); QRegExp regexp("^(:?NORM|EVEN|PARK|MANU)[0-9]{6}-[0-9]{6}(:?FR|LS|RR|RS|IN)"); // EX->IN 으로 변경 regexp.setCaseSensitivity(Qt::CaseInsensitive); // 240523-174742 if(regexp.exactMatch(baseName)) { if(baseName.startsWith("EVEN")) { *type = TYPE_EVENT; } else if(baseName.startsWith("PARK")) { *type = TYPE_PARKING; } else if(baseName.startsWith("MANU")) { *type = TYPE_MANUAL; }else { *type = TYPE_NORMAL; } } return baseName; } QString RMVideoFileList::_checkChannelInfo(QString filePath,int *ch) { QString baseName = QFileInfo(filePath).baseName(); QRegExp regexp("^(:?NORM|EVEN|PARK|MANU)[0-9]{6}-[0-9]{6}(:?FR|LS|RR|RS|IN)"); // EX->IN 으로 변경 if(regexp.exactMatch(baseName)) { if(baseName.endsWith("FR")) { *ch = (int)RMApp::ChannelFront; } else if(baseName.endsWith("RR")) { *ch = (int)RMApp::ChannelRear; } else if(baseName.endsWith("LS")) { *ch = (int)RMApp::ChannelLeft; } else if(baseName.endsWith("RS")) { *ch = (int)RMApp::ChannelRight; } else if(baseName.endsWith("IN")) { *ch = (int)RMApp::ChannelSub; } } // 동일한 영상/전후방 비교용으로만 사용됨 baseName.truncate(baseName.length()-2); return baseName; } bool RMVideoFileList::_addOtherChannelFile(RMVideoItem *item) { QString filePath = item->anyFilePath(); QString fileFolder = QFileInfo(filePath).absolutePath(); // 탐색폴더 확인 bool found = false; int ch = -1; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&ch); if(ch >= 0 && ch <= 4) { //QStringList searchFileNames = QStringList(); QStringList searchFileNames = QStringList() << "FR.mp4" << "RR.mp4" << "LS.mp4" << "RS.mp4" << "IN.mp4"; // EX->IN // RR 이 먼저 확인되어도 모두 처리가능하도록 변경 // searchFileNames.removeAt(ch); foreach (QString path, searchFileNames) { //qInfo() << baseName << path << __FUNCTION__; QString fullPath = QDir::cleanPath((fileFolder + QDir::separator() + baseName + path)); if( QFile::exists(fullPath) ) { int fc = 0; RMVideoFileList::_checkChannelInfo(fullPath,&fc); if(fc == 0) { item->filePath = fullPath; } else if (fc == 1) { item->filePathCH2 = fullPath; } else if (fc == 2) { item->filePathCH3 = fullPath; } else if (fc == 3) { item->filePathCH4 = fullPath; } else if (fc == 4) { item->filePathCH5 = fullPath; } found = true; } } } return found; } #elif (RM_MODEL_EMT_KR) RMVideoFileList::GROUP_TYPE RMVideoFileList::parseName(QString baseName, QDateTime* dateTime, int* tag) { if(tag != NULL) { *tag = 0; } if(dateTime != NULL) { dateTime->swap(QDateTime()); // INVALID } // 상시폴더 // 250610_18h14m35s_Driving_sde.MP4 (일본향 sdexit, 파일 생성시) // 250610_18h02m35s_Driving.MP4 (정상 종료) // 250610_18h00m30s_Driving_res.MP4 (복구 파일) // 상시 이벤트 // 250610_18h18m29s_EventShock.MP4 (상시 이벤트) // 매뉴얼 이벤트 // 250610_18h17m36s_Manual.MP4 (매뉴얼 이벤트 ) // 주차폴더 // 250610_18h18m09s_Parking.MP4 // 250610_18h18m09s_Parkin_htp.MP4 (고온종료) // 250610_18h18m09s_Parkin_lbp.MP4 (차단전압)" // ParkingShock 이 Parking 보다 먼저 사용되어야 함 static QRegularExpression rx("^(?P\\d{6})_(?P\\d{2})h(?P\\d{2})m(?P\\d{2})s_(?PDriving|EventShock|EventAI|Manual|ParkingShock|Parking)(?:_(?Pres|htp|lbp|RC|CD))?",QRegularExpression::CaseInsensitiveOption); QRegularExpressionMatch match = rx.match(baseName); if (!match.isValid()) { return TYPE_UNDEFINED; } // 날짜 처리 if(dateTime != NULL) { QString dateString = "20" + match.captured("ymd") + "_" + match.captured("hour") + match.captured("minutes") + match.captured("second"); dateTime->swap(QDateTime::fromString(dateString,"yyyyMMdd_HHmmss")); } // 태그 처리 if(tag != NULL && !match.captured("tag").isEmpty()) { QString tagString = match.captured("tag").toLower(); // res = 1|htp = 2|lbp = 3 if(tagString == "res") { *tag = 1; } else if(tagString == "htp") { *tag = 2; } else if(tagString == "lbp") { *tag = 3; } else if(tagString == "rc") { //후방추돌 *tag = 4; } else if(tagString == "cd") { // 끼어들기 *tag = 5; } } QString typeString = match.captured("type").toLower(); //qInfo() << baseName << typeString << match.captured("tag") << __FUNCTION__; if(typeString == "driving") { return TYPE_NORMAL; } else if (typeString == "eventshock" || typeString == "eventai") { return TYPE_EVENT; } else if (typeString == "manual") { return TYPE_MANUAL; } else if (typeString == "parking") { return TYPE_PARKING; } else if (typeString == "parkingshock") { return TYPE_PARKING_EVENT; } return TYPE_UNDEFINED; } QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { // 20250528_13h42m07s_Driving QString baseName = QFileInfo(QDir::cleanPath(filePath)).baseName(); *type = parseName(baseName,NULL,NULL); QString folderName = QFileInfo(filePath).dir().dirName().toUpper(); if(folderName == "MYBOX") { *type = RMVideoFileList::TYPE_MY_BOX; } return baseName; } #elif (RM_MODEL == RM_MODEL_TYPE_TB4000) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString baseName = QFileInfo(QDir::cleanPath(filePath)).baseName(); // 20230815-070258_REC_0000.mp4 *type = TYPE_NORMAL; return baseName; } #elif (RM_MODEL == RM_MODEL_TYPE_KEIYO1 || RM_MODEL == RM_MODEL_TYPE_MBJ5010 || RM_MODEL == RM_MODEL_TYPE_FC_DR232W || RM_MODEL == RM_MODEL_TYPE_BV2000) #if !(FORCE_2CH) #if (TRI_CHANNEL) QString RMVideoFileList::_checkChannelInfo(QString filePath,int *ch) #else QString RMVideoFileList::_checkChannelInfo(QString filePath,bool *isCH2, bool *is2CH) #endif { QString baseName = QFileInfo(filePath).baseName(); #if (TRI_CHANNEL) if(ch != NULL) { if(baseName.endsWith("R",Qt::CaseInsensitive)) { *ch = 2; } else if(baseName.endsWith("I",Qt::CaseInsensitive)) { *ch = 3; } else { *ch = 1; } } #else // TRI_CHANNEL if(isCH2 != NULL) { if(baseName.endsWith("R",Qt::CaseInsensitive)) { *isCH2 = true; } else { *isCH2 = false; } } #endif // #if (TRI_CHANNEL) #if (SUPPORT_2CH) if(is2CH != NULL) { *is2CH = baseName.endsWith("W",Qt::CaseInsensitive); } #endif // SUPPORT_2CH // 동일한 영상/전후방 비교용으로만 사용됨 baseName.truncate(baseName.length()-1); return baseName; } // 전방 또는 후방 파일 확인해서 추가 bool RMVideoFileList::_addOtherChannelFile(RMVideoItem *item) { QString filePath = item->anyFilePath(); QString fileFolder = QFileInfo(filePath).absolutePath(); #if (TRI_CHANNEL) int ch; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&ch); QStringList searchFileNames = QStringList(); if (ch == 1) { searchFileNames << "R.mp4" << "I.mp4"; } else if (ch == 2) { searchFileNames << "F.mp4" << "I.mp4"; } else if (ch == 3) { searchFileNames << "F.mp4" << "R.mp4"; } //QStringList searchPaths = QStringList() << QDir::cleanPath((fileFolder + QDir::separator() + searchFileName)); // 탐색폴더 확인 bool found = false; foreach (QString path, searchFileNames) { QString fullPath = QDir::cleanPath((fileFolder + QDir::separator() + baseName + path)); if( QFile::exists(fullPath) ) { int fc = 0; RMVideoFileList::_checkChannelInfo(fullPath,&fc); if(fc == 1) { item->filePath = fullPath; } else if (fc == 2) { item->filePathCH2 = fullPath; } else if (fc == 3) { item->filePathCH3 = fullPath; } found = true; } } return found; #else QString searchFileName; bool isCH2 = false; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&isCH2); // 탐색할 파일명 searchFileName = baseName + (isCH2 ? "F.mp4" : "R.mp4"); QStringList searchPaths = QStringList() << QDir::cleanPath((fileFolder + QDir::separator() + searchFileName)); // 폴더의 폴더 // QString fileFolderFolder = QFileInfo(fileFolder).baseName(); // if(fileFolderFolder == "F" || fileFolderFolder == "R") { // QString searchFolder = (fileFolderFolder == "F" ? "R" : "F"); // searchPaths << (QDir::cleanPath(QFileInfo(fileFolder).absolutePath() + QDir::separator() + searchFolder + QDir::separator() + searchFileName)); // } // 탐색폴더 확인 foreach (QString path, searchPaths) { if( QFile::exists(path) ) { if(isCH2) { item->filePath = path; } else { item->filePathCH2 = path; } return true; } } return false; #endif } #endif // #if !(FORCE_2CH) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); #if (SUB_MODEL_KEIYO_360) // NORM230517-104840I.MP4 QRegExp regexp("^(NORM|EVEN)[0-9]{6}-[0-9]{6}[I,W]"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } if(baseName.startsWith("NORM")) { *type = TYPE_NORMAL; } else if (baseName.startsWith("EVEN")) { *type = TYPE_EVENT; } return baseName.mid(4,6+1+6); #else // #if (SUB_MODEL_KEIYO_360) // NORM201029-085403F // EVEN201029-085721F // MANU201029-090032F // PARK201029-091752F // PEVE190116-173653F.MP4 // 주차 이벤트 // PNOR190120-211045F.MP4 // 주차 상시 #if (SUPPORT_2CH || FORCE_2CH) QRegExp regexp("^[N,E,M,P][O,V,A,E,N][R,E,N,V,O][M,N,U,K,E,R][0-9]{6}-[0-9]{6}[F,R,W]"); #else QRegExp regexp("^[N,E,M,P][O,V,A,E,N][R,E,N,V,O][M,N,U,K,E,R][0-9]{6}-[0-9]{6}[F,R]"); #endif if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } if(baseName.startsWith("NORM")) { *type = TYPE_NORMAL; } else if (baseName.startsWith("EVEN")) { *type = TYPE_EVENT; } else if (baseName.startsWith("MANU")) { *type = TYPE_MANUAL; } else if (baseName.startsWith("PARK")) { *type = TYPE_PARKING; } else if (baseName.startsWith("PNOR")) { // 벤츠2 *type = TYPE_PARKING; } else if (baseName.startsWith("PEVE")) { // 벤츠2 *type = TYPE_PARKING_EVENT; } else { *type = TYPE_NORMAL; } return baseName.mid(4,13); #endif // #else // #if (SUB_MODEL_KEIYO_360) } #elif (RM_MODEL == RM_MODEL_TYPE_ADT_CAPS && !SUB_MODEL_CARROT_EMT) QString RMVideoFileList::_checkChannelInfo(QString filePath,bool *isCH2, bool *is2CH) { QString baseName = QFileInfo(filePath).baseName(); if(isCH2 != NULL) { *isCH2 = baseName.contains("_R_",Qt::CaseInsensitive); } // 동일한 영상/전후방 비교용으로만 사용됨 baseName = baseName.replace("_R_","_#CH#_").replace("_F_","_#CH#_"); return baseName; } bool RMVideoFileList::_addOtherChannelFile(RMVideoItem *item) { QString filePath = item->anyFilePath(); QString fileFolder = QFileInfo(filePath).absolutePath(); bool isCH2 = false; QString searchFileName; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&isCH2); // 탐색할 파일명 searchFileName = baseName.replace("_#CH#_",isCH2 ? "_F_" : "_R_") + "." + FILE_EXT; QStringList searchPaths = QStringList() << QDir::cleanPath((fileFolder + QDir::separator() + searchFileName)); // 폴더의 폴더 QString fileFolderFolder = QFileInfo(fileFolder).baseName(); if(fileFolderFolder == "1" || fileFolderFolder == "2") { QString searchFolder = (fileFolderFolder == "1" ? "2" : "1"); searchPaths << (QDir::cleanPath(QFileInfo(fileFolder).absolutePath() + QDir::separator() + searchFolder + QDir::separator() + searchFileName)); } // 탐색폴더 확인 foreach (QString path, searchPaths) { if( QFile::exists(path) ) { if(isCH2) { item->filePath = path; } else { item->filePathCH2 = path; } } } return true; } QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); // 2020-06-12-17h-10m-05s_F_normal.mp4 QRegExp regexp("^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}H-[0-9]{2}M-[0-9]{2}S_[F,R]_[A-Z]*"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } if(baseName.endsWith("_NORMAL",Qt::CaseInsensitive)) { *type = TYPE_NORMAL; } else { *type = TYPE_EVENT; } baseName.truncate(22); // 2020-06-12-17H-10M-05S return baseName; } #elif (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); // S200727_110830FE_Exit // S200526_110830FP // S200727_100830FE_Exit // S200827_100830FN_Exit // 2021/07/21 추가 // S210217_001749FN_TEMP // + _TEMP,_RCVR,_MENU,_LBAT // S210217_001548FPE : 주차 충격 QRegExp regexp("^[S][0-9]{6}_[0-9]{6}[F][P,E,N,PE][_EXIT,_TEMP,_RCVR,_MENU,_LBAT,_PKTM]*"); // if(!regexp.exactMatch(baseName)) { qInfo() << "FILE ERROR:" << baseName << __FUNCTION__ << __LINE__; *type = TYPE_UNDEFINED; return ""; } QString typeString = baseName.mid(14,2).toUpper(); if(typeString == "FN") { *type = TYPE_NORMAL; } else if(typeString == "FP") { if (baseName.length() > 16 && baseName.mid(16,1).toUpper() == "E") { // FPE (PARKING EVENT) *type = TYPE_PARKING; // 주차 충격은 주차로 이동 } else { *type = TYPE_PARKING; } } else { *type = TYPE_EVENT; } // qInfo() << filePath << "TYPE:" << *type; return baseName.mid(1,13); } #elif (RM_MODEL == RM_MODEL_TYPE_AN6000) int RMVideoFileList::parseSerial(QString baseName) { // 2023-12-31-07h-14m-07s_normal_1(1) 모두 처리 static QRegularExpression rx("^(?P\\d{4}-\\d{2}-\\d{2}-\\d{2}h-\\d{2}m-\\d{2}s)_normal(_(?P\\d{1,2}))?(\\((?P\\d{1,2})\\))?",QRegularExpression::CaseInsensitiveOption); QRegularExpressionMatch match = rx.match(baseName); if (!match.isValid()) { return -1; } // 날짜 처리 -> 필요없음 //if(0) { //dateTime->swap(QDateTime::fromString(match.captured("datetime"),"yyyy-MM-dd-HH'h'-mm'm'-ss's'")); //} int serial = 0; if(!match.captured("index").isEmpty()) { // _1 serial = match.captured("index").toInt(); } if(!match.captured("index2").isEmpty()) { // _1(2) serial += match.captured("index2").toInt() + 100; } return serial; } QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type, int* serial) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); *serial = parseSerial(baseName); if(*serial < 0) { *type = TYPE_UNDEFINED; return ""; } if(baseName.contains("_NORMAL",Qt::CaseInsensitive)) { *type = TYPE_NORMAL; } else { *type = TYPE_EVENT; } baseName.truncate(22); return baseName; /* // 2020-06-12-17h-10m-05s_F_normal.mp4 // 2020-06-12-17h-10m-05s_F_normal(1).mp4 2024/09/24 추가 // 2020-06-12-17h-10m-05s_F_normal_1.mp4 2026/09/06 추가 // 2020-06-12-17h-10m-05s_F_normal_1(1).mp4 2026/09/06 추가 // QRegExp 는 '(' 문자는 [\(] 로만 처리됨 QRegExp regexp("^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}H-[0-9]{2}M-[0-9]{2}S_NORMAL([\(]{1}[1-9]{1}[\)]{1})?"); regexp.setCaseSensitivity(Qt::CaseInsensitive); if(!regexp.exactMatch(baseName)) { //qInfo() << "NO GROUP MATCH:" << baseName << __FUNCTION__; *type = TYPE_UNDEFINED; return ""; } //qInfo() << baseName << __FUNCTION__; // (1)~(9) 처리 if(baseName.endsWith(")")) { QStringList lst = baseName.split("("); QString number = lst.last().replace(")",""); if(serial != NULL) { *serial = number.toInt(); } baseName = lst.first(); //qInfo() << "BASENAME:" << baseName << number << __FUNCTION__; } if(baseName.endsWith("_NORMAL",Qt::CaseInsensitive)) { *type = TYPE_NORMAL; } else { *type = TYPE_EVENT; } baseName.truncate(22); // 2020-06-12-17H-10M-05S return baseName; */ } // RM_MODEL_TYPE_AN6000 #elif (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); // S200727_110830FE_Exit // S200526_110830FP // S200727_100830FE_Exit // S200827_100830FN_Exit // 2021/07/21 추가 // S210217_001749FN_TEMP // + _TEMP,_RCVR,_MENU,_LBAT // S210217_001548FPE : 주차 충격 QRegExp regexp("^[S][0-9]{6}_[0-9]{6}[F][P,E,N,PE][_EXIT,_TEMP,_RCVR,_MENU,_LBAT,_PKTM]*"); // if(!regexp.exactMatch(baseName)) { qInfo() << "FILE ERROR:" << baseName << __FUNCTION__ << __LINE__; *type = TYPE_UNDEFINED; return ""; } QString typeString = baseName.mid(14,2).toUpper(); if(typeString == "FN") { *type = TYPE_NORMAL; } else if(typeString == "FP") { if (baseName.length() > 16 && baseName.mid(16,1).toUpper() == "E") { // FPE (PARKING EVENT) *type = TYPE_PARKING; // 주차 충격은 주차로 이동 } else { *type = TYPE_PARKING; } } else { *type = TYPE_EVENT; } // qInfo() << filePath << "TYPE:" << *type; return baseName.mid(1,13); } #elif (RM_MODEL == RM_MODEL_TYPE_TBD360) #if (!FORCE_2CH || (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT)) QString RMVideoFileList::_checkChannelInfo(QString filePath,bool *isCH2, bool *is2CH) { QString baseName = QFileInfo(filePath).baseName(); if(isCH2 != NULL) { *isCH2 = baseName.contains("_R_",Qt::CaseInsensitive); } // 동일한 영상/전후방 비교용으로만 사용됨 baseName = baseName.replace("_R_","_#CH#_").replace("_F_","_#CH#_"); return baseName; } bool RMVideoFileList::_addOtherChannelFile(RMVideoItem *item) { QString filePath = item->anyFilePath(); QString fileFolder = QFileInfo(filePath).absolutePath(); bool isCH2 = false; QString searchFileName; QString baseName = RMVideoFileList::_checkChannelInfo(filePath,&isCH2); // 탐색할 파일명 searchFileName = baseName.replace("_#CH#_",isCH2 ? "_F_" : "_R_") + "." + FILE_EXT; QStringList searchPaths = QStringList() << QDir::cleanPath((fileFolder + QDir::separator() + searchFileName)); // 폴더의 폴더 QString fileFolderFolder = QFileInfo(fileFolder).baseName(); if(fileFolderFolder == "Front" || fileFolderFolder == "Rear") { QString searchFolder = (fileFolderFolder == "Front" ? "Rear" : "Front"); searchPaths << (QDir::cleanPath(QFileInfo(fileFolder).absolutePath() + QDir::separator() + searchFolder + QDir::separator() + searchFileName)); } // 탐색폴더 확인 foreach (QString path, searchPaths) { if( QFile::exists(path) ) { if(isCH2) { item->filePath = path; } else { item->filePathCH2 = path; } return true; } } return false; } #endif // #if (!FORCE_2CH || (RM_MODEL == RM_MODEL_TYPE_XLDR_88 || SUB_MODEL_CARROT_EMT)) QString RMVideoFileList::groupTypeFromFilePath(QString filePath,RMVideoFileList::GROUP_TYPE* type) { QString cleanPath = filePath.toUpper(); QString baseName = QFileInfo(cleanPath).baseName(); #if (TANDF_360_TEST) // NNF_210212-101925-000055_1.MP4 QRegExp regexp("^[A-Z]{3}_[0-9]{6}-[0-9]{6}-[0-9]{6}_[1,2]{1}"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } *type = TYPE_NORMAL; // NNF_210212-101925-000055_1 return baseName.mid(4,6+1+6); #elif (THINKWARE_DEMO) // 20231102_141152E .MP4 QRegExp regexp("^[0-9]{8}_[0-9]{6}[E,M,N]{1}"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } *type = TYPE_NORMAL; // NNF_210212-101925-000055_1 return baseName.mid(0,15); #elif (TEST_FILENAME) QRegExp regexp("^TEST_[0-9]{8}-[0-9]{6}"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } *type = TYPE_NORMAL; return baseName.mid(5,8+1+6); #elif (MH_360_TEST) // NORM230517-104840I.MP4 QRegExp regexp("^NORM[0-9]{6}-[0-9]{6}I"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } *type = TYPE_NORMAL; return baseName.mid(4,6+1+6); #else // TANDF_360_TEST // 20201208_215045_F_Nor.AVI // 20201208_151241_F_Gsn.AVI QRegExp regexp("^[0-9]{8}_[0-9]{6}_[F,R]_[A-z]*"); if(!regexp.exactMatch(baseName)) { *type = TYPE_UNDEFINED; return ""; } if(baseName.endsWith("_Nor",Qt::CaseInsensitive)) { *type = TYPE_NORMAL; } else if(baseName.endsWith("_Gsn",Qt::CaseInsensitive)) { *type = TYPE_EVENT; } else { *type = TYPE_NORMAL; } baseName.truncate(15); // 20201208_151241 #endif // TANDF_360_TEST return baseName; } #endif // MODEL