BOOL CDecodeUtil::CheckTDT(WORD PID, CTDTTable* tdt) { if( tdt == NULL ){ return FALSE; } SAFE_DELETE(this->tdtInfo); this->tdtInfo = tdt; __int64 nowTime = GetNowI64Time(); __int64 streamTime = ConvertI64Time( tdt->jst_time ); this->delaySec = (int)((streamTime - nowTime)/I64_1SEC); /* _OutputDebugString(L"%d/%02d/%02d %02d:%02d:%02d\r\n", tdt->jst_time.wYear, tdt->jst_time.wMonth, tdt->jst_time.wDay, tdt->jst_time.wHour, tdt->jst_time.wMinute, tdt->jst_time.wSecond );*/ return TRUE; }
BOOL CDecodeUtil::CheckSIT(WORD PID, CSITTable* sit) { if( sit == NULL ){ return FALSE; } //時間計算 if( this->totInfo == NULL && this->tdtInfo == NULL ){ for( size_t i=0; i<sit->descriptorList.size(); i++ ){ if( sit->descriptorList[i]->GetNumber(AribDescriptor::descriptor_tag) == AribDescriptor::partialTS_time_descriptor ){ if( sit->descriptorList[i]->GetNumber(AribDescriptor::jst_time_flag) == 1 ){ DWORD timeBytesSize; const BYTE* timeBytes = sit->descriptorList[i]->GetBinary(AribDescriptor::jst_time, &timeBytesSize); if( timeBytes != NULL && timeBytesSize >= 5 ){ DWORD mjd = timeBytes[0] << 8 | timeBytes[1]; SYSTEMTIME time; _MJDtoSYSTEMTIME(mjd, &time); BYTE b = timeBytes[2]; time.wHour = (WORD)_BCDtoDWORD(&b, 1, 2); b = timeBytes[3]; time.wMinute = (WORD)_BCDtoDWORD(&b, 1, 2); b = timeBytes[4]; time.wSecond = (WORD)_BCDtoDWORD(&b, 1, 2); __int64 nowTime = GetNowI64Time(); __int64 streamTime = ConvertI64Time(time); this->delaySec = (int)((streamTime - nowTime)/I64_1SEC); } } } } } if( epgDBUtil != NULL ){ if( this->patInfo != NULL ){ epgDBUtil->AddServiceList(this->patInfo->transport_stream_id, sit); } } if( this->sitInfo == NULL ){ //初回 this->sitInfo = sit; }else{ if( this->sitInfo->version_number != sit->version_number ){ //バージョン変わった SAFE_DELETE(this->sitInfo); this->sitInfo = sit; }else{ //変化なし return FALSE; } } return TRUE; }
bool CTunerBankCtrl::IsNeedOpenTuner() const { if( this->specialState != TR_IDLE ){ return true; } //戻り値の振動を防ぐためdelayTimeを考慮してはいけない __int64 now = GetNowI64Time(); for( map<DWORD, TUNER_RESERVE>::const_iterator itr = this->reserveMap.begin(); itr != this->reserveMap.end(); itr++ ){ if( itr->second.state != TR_IDLE || (itr->second.startTime - itr->second.startMargin - this->recWakeTime) / I64_1SEC < now / I64_1SEC ){ return true; } } return false; }
bool CTunerBankCtrl::ChgCtrlReserve(TUNER_RESERVE* reserve) { map<DWORD, TUNER_RESERVE>::iterator itr = this->reserveMap.find(reserve->reserveID); if( itr != this->reserveMap.end() && itr->second.state != TR_IDLE ){ //内部パラメータを退避 TUNER_RESERVE save = itr->second; //変更できないフィールドを上書き reserve->onid = save.onid; reserve->tsid = save.tsid; reserve->sid = save.sid; //プログラム予約への変更のみ認める if( reserve->eid != 0xFFFF ){ reserve->eid = save.eid; } reserve->recMode = save.recMode; reserve->priority = save.priority; reserve->enableCaption = save.enableCaption; reserve->enableData = save.enableData; reserve->pittari = save.pittari; reserve->partialRecMode = save.partialRecMode; reserve->recFolder = save.recFolder; reserve->partialRecFolder = save.partialRecFolder; //後方移動は注意。なお前方移動はどれだけ大きくても次のCheck()で予約終了するだけなので問題ない if( reserve->startTime - reserve->startMargin > save.startTime - save.startMargin ){ __int64 now = GetNowI64Time() + this->delayTime; if( reserve->startTime - reserve->startMargin - 60 * I64_1SEC > now ){ reserve->startTime = save.startTime; reserve->startMargin = save.startMargin; } } TUNER_RESERVE& r = itr->second = *reserve; //内部パラメータを復元 r.startOrder = (r.startTime - r.startMargin) / I64_1SEC << 16 | r.reserveID & 0xFFFF; r.effectivePriority = (this->backPriority ? -1 : 1) * ((__int64)((this->backPriority ? r.priority : ~r.priority) & 7) << 60 | r.startOrder); r.state = save.state; r.retryOpenCount = save.retryOpenCount; r.ctrlID[0] = save.ctrlID[0]; r.ctrlID[1] = save.ctrlID[1]; r.notStartHead = save.notStartHead; r.appendPgInfo = save.appendPgInfo; r.savedPgInfo = save.savedPgInfo; r.epgStartTime = save.epgStartTime; r.epgEventName = save.epgEventName; return true; } return false; }
UINT WINAPI CEpgDBManager::LoadThread(LPVOID param) { CEpgDBManager* sys = (CEpgDBManager*)param; OutputDebugString(L"Start Load EpgData\r\n"); DWORD time = GetTickCount(); CEpgDataCap3Util epgUtil; if( epgUtil.Initialize(FALSE) == FALSE ){ OutputDebugString(L"★EpgDataCap3.dllの初期化に失敗しました。\r\n"); return 0; } //EPGファイルの検索 vector<wstring> epgFileList; wstring epgDataPath = L""; GetSettingPath(epgDataPath); epgDataPath += EPG_SAVE_FOLDER; wstring searchKey = epgDataPath; searchKey += L"\\*_epg.dat"; WIN32_FIND_DATA findData; HANDLE find; //指定フォルダのファイル一覧取得 find = FindFirstFile( searchKey.c_str(), &findData); if ( find == INVALID_HANDLE_VALUE ) { //1つも存在しない epgUtil.UnInitialize(); return 0; } do{ if( (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ){ //本当に拡張子DLL? if( IsExt(findData.cFileName, L".dat" ) == TRUE ){ //見つかったファイルを一覧に追加 wstring epgFilePath = L""; Format(epgFilePath, L"%s\\%s", epgDataPath.c_str(), findData.cFileName); epgFileList.push_back(epgFilePath); } } }while(FindNextFile(find, &findData)); FindClose(find); //EPGファイルの解析 for( size_t i=0; i<epgFileList.size(); i++ ){ HANDLE file = _CreateFile( epgFileList[i].c_str(), GENERIC_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( file != INVALID_HANDLE_VALUE ){ FILETIME CreationTime; FILETIME LastAccessTime; FILETIME LastWriteTime; GetFileTime(file, &CreationTime, &LastAccessTime, &LastWriteTime); LONGLONG fileTime = ((LONGLONG)LastWriteTime.dwHighDateTime)<<32 | (LONGLONG)LastWriteTime.dwLowDateTime; if( fileTime + 7*24*60*60*I64_1SEC < GetNowI64Time() ){ //1週間以上前のファイルなので削除 CloseHandle(file); DeleteFile( epgFileList[i].c_str() ); _OutputDebugString(L"★delete %s", epgFileList[i].c_str()); }else{ DWORD fileSize = GetFileSize( file, NULL ); BYTE readBuff[188*1024]; DWORD readSize = 0; while( readSize < fileSize ){ if( ::WaitForSingleObject(sys->loadStopEvent, 0) != WAIT_TIMEOUT ){ //キャンセルされた CloseHandle(file); epgUtil.UnInitialize(); return 0; } DWORD read=0; ReadFile( file, &readBuff, 188*1024, &read, NULL ); for( DWORD i=0; i<read; i+=188 ){ epgUtil.AddTSPacket(readBuff+i, 188); } readSize+=read; Sleep(0); } CloseHandle(file); } } Sleep(0); } //EPGデータを取得 DWORD serviceListSize = 0; SERVICE_INFO* serviceList = NULL; if( epgUtil.GetServiceListEpgDB(&serviceListSize, &serviceList) == FALSE ){ epgUtil.UnInitialize(); return 0; } for( DWORD i=0; i<serviceListSize; i++ ){ LONGLONG key = _Create64Key(serviceList[i].original_network_id, serviceList[i].transport_stream_id, serviceList[i].service_id); EPGDB_SERVICE_DATA* item = new EPGDB_SERVICE_DATA; item->serviceInfo.ONID = serviceList[i].original_network_id; item->serviceInfo.TSID = serviceList[i].transport_stream_id; item->serviceInfo.SID = serviceList[i].service_id; if( serviceList[i].extInfo != NULL ){ item->serviceInfo.service_type = serviceList[i].extInfo->service_type; item->serviceInfo.partialReceptionFlag = serviceList[i].extInfo->partialReceptionFlag; if( serviceList[i].extInfo->service_provider_name != NULL ){ item->serviceInfo.service_provider_name = serviceList[i].extInfo->service_provider_name; } if( serviceList[i].extInfo->service_name != NULL ){ item->serviceInfo.service_name = serviceList[i].extInfo->service_name; } if( serviceList[i].extInfo->network_name != NULL ){ item->serviceInfo.network_name = serviceList[i].extInfo->network_name; } if( serviceList[i].extInfo->ts_name != NULL ){ item->serviceInfo.ts_name = serviceList[i].extInfo->ts_name; } item->serviceInfo.remote_control_key_id = serviceList[i].extInfo->remote_control_key_id; } sys->epgMap.insert(pair<LONGLONG, EPGDB_SERVICE_DATA*>(key, item)); DWORD epgInfoListSize = 0; EPG_EVENT_INFO* epgInfoList = NULL; if( epgUtil.GetEpgInfoList(item->serviceInfo.ONID, item->serviceInfo.TSID, item->serviceInfo.SID, &epgInfoListSize, &epgInfoList) == TRUE ){ for( DWORD j=0; j<epgInfoListSize; j++ ){ EPGDB_EVENT_INFO* itemEvent = new EPGDB_EVENT_INFO; sys->ConvertEpgInfo(item->serviceInfo.ONID, item->serviceInfo.TSID, item->serviceInfo.SID, epgInfoList+j, itemEvent); item->eventMap.insert(pair<WORD, EPGDB_EVENT_INFO*>(itemEvent->event_id, itemEvent)); } } Sleep(0); } _OutputDebugString(L"End Load EpgData %dmsec\r\n", GetTickCount()-time); epgUtil.UnInitialize(); return 0; }
vector<CTunerBankCtrl::CHECK_RESULT> CTunerBankCtrl::Check(vector<DWORD>* startedReserveIDList) { vector<CHECK_RESULT> retList; if( this->hTunerProcess && WaitForSingleObject(this->hTunerProcess, 0) != WAIT_TIMEOUT ){ //チューナが予期せず閉じられた CloseTuner(); this->specialState = TR_IDLE; //TR_IDLEでない全予約を葬る for( map<DWORD, TUNER_RESERVE>::const_iterator itr = this->reserveMap.begin(); itr != this->reserveMap.end(); ){ if( itr->second.state != TR_IDLE ){ CHECK_RESULT ret; ret.type = CHECK_ERR_REC; ret.reserveID = itr->first; retList.push_back(ret); this->reserveMap.erase(itr++); }else{ itr++; } } } CWatchBlock watchBlock(&this->watchContext); CSendCtrlCmd ctrlCmd; if( this->hTunerProcess ){ //チューナ起動時にはこれを再度呼ぶこと ctrlCmd.SetPipeSetting(CMD2_VIEW_CTRL_WAIT_CONNECT, CMD2_VIEW_CTRL_PIPE, this->tunerPid); } if( this->specialState == TR_EPGCAP ){ DWORD status; if( ctrlCmd.SendViewGetStatus(&status) == CMD_SUCCESS ){ if( status != VIEW_APP_ST_GET_EPG ){ //取得終わった OutputDebugString(L"epg end\r\n"); CloseTuner(); this->specialState = TR_IDLE; } }else{ //エラー OutputDebugString(L"epg err\r\n"); CloseTuner(); this->specialState = TR_IDLE; } }else if( this->specialState == TR_NWTV ){ //ネットワークモードではGUIキープできないのでBonDriverが変更されるかもしれない //BonDriverが変更されたチューナはこのバンクの管理下に置けないので、ネットワークモードを解除する wstring bonDriver; if( ctrlCmd.SendViewGetBonDrivere(&bonDriver) == CMD_SUCCESS && CompareNoCase(bonDriver, this->bonFileName) != 0 ){ if( ctrlCmd.SendViewSetID(-1) == CMD_SUCCESS ){ CBlockLock lock(&this->watchContext.lock); CloseHandle(this->hTunerProcess); this->hTunerProcess = NULL; this->specialState = TR_IDLE; }else{ //ID剥奪に失敗したので消えてもらうしかない CloseNWTV(); } //TODO: 汎用のログ用メッセージが存在しないので、やむを得ずNOTIFY_UPDATE_REC_ENDで警告する this->notifyManager.AddNotifyMsg(NOTIFY_UPDATE_REC_END, L"BonDriverが変更されたためNetworkモードを解除しました\r\n変更したBonDriverに録画の予定がないか注意してください"); } }else if( this->hTunerProcess && this->tunerChLocked == false ){ //GUIキープされていないのでBonDriverが変更されるかもしれない wstring bonDriver; if( ctrlCmd.SendViewGetBonDrivere(&bonDriver) == CMD_SUCCESS && CompareNoCase(bonDriver, this->bonFileName) != 0 ){ if( ctrlCmd.SendViewSetID(-1) == CMD_SUCCESS ){ CBlockLock lock(&this->watchContext.lock); CloseHandle(this->hTunerProcess); this->hTunerProcess = NULL; }else{ //ID剥奪に失敗したので消えてもらうしかない CloseTuner(); } //TR_IDLEでない全予約を葬る for( map<DWORD, TUNER_RESERVE>::const_iterator itr = this->reserveMap.begin(); itr != this->reserveMap.end(); ){ if( itr->second.state != TR_IDLE ){ CHECK_RESULT ret; ret.type = CHECK_ERR_REC; ret.reserveID = itr->first; retList.push_back(ret); this->reserveMap.erase(itr++); }else{ itr++; } } } } this->delayTime = 0; this->epgCapDelayTime = 0; if( this->hTunerProcess && this->specialState != TR_NWTV ){ //PC時計との誤差取得 int delaySec; if( ctrlCmd.SendViewGetDelay(&delaySec) == CMD_SUCCESS ){ //誤った値を掴んでおかしなことにならないよう、EPG取得中の値は状態遷移の参考にしない if( this->specialState == TR_EPGCAP ){ this->epgCapDelayTime = delaySec * I64_1SEC; }else{ this->delayTime = delaySec * I64_1SEC; } } } __int64 now = GetNowI64Time() + this->delayTime; //終了時間を過ぎた予約を回収し、TR_IDLE->TR_READY以外の遷移をする vector<pair<__int64, DWORD>> idleList; bool ngResetLock = false; for( map<DWORD, TUNER_RESERVE>::iterator itrRes = this->reserveMap.begin(); itrRes != this->reserveMap.end(); ){ TUNER_RESERVE& r = itrRes->second; CHECK_RESULT ret; ret.type = 0; switch( r.state ){ case TR_IDLE: if( r.startTime + r.endMargin + r.durationSecond * I64_1SEC < now ){ ret.type = CHECK_ERR_PASS; } //開始順が秒精度なので、前後関係を確実にするため開始時間は必ず秒精度で扱う else if( (r.startTime - r.startMargin - this->recWakeTime) / I64_1SEC < now / I64_1SEC ){ //録画開始recWakeTime前〜 idleList.push_back(std::make_pair(r.startOrder, r.reserveID)); } break; case TR_READY: if( r.startTime + r.endMargin + r.durationSecond * I64_1SEC < now ){ for( int i = 0; i < 2; i++ ){ if( r.ctrlID[i] != 0 ){ ctrlCmd.SendViewDeleteCtrl(r.ctrlID[i]); } } ret.type = CHECK_ERR_PASS; } //パイプコマンドにはチャンネル変更の完了を調べる仕組みがないので、妥当な時間だけ待つ else if( GetTickCount() - this->tunerChChgTick > 5000 && r.startTime - r.startMargin < now ){ //録画開始〜 if( RecStart(r, now) ){ //途中から開始されたか r.notStartHead = r.startTime - r.startMargin + 60 * I64_1SEC < now; r.appendPgInfo = false; r.savedPgInfo = false; r.state = TR_REC; if( r.recMode == RECMODE_VIEW ){ //視聴予約でない予約が1つでもあれば「視聴モード」にしない map<DWORD, TUNER_RESERVE>::const_iterator itr; for( itr = this->reserveMap.begin(); itr != this->reserveMap.end(); itr++ ){ if( itr->second.state != TR_IDLE && itr->second.recMode != RECMODE_VIEW ){ break; } } if( itr == this->reserveMap.end() ){ //「視聴モード」にするとGUIキープが解除されてしまうためチャンネルを把握することはできない ctrlCmd.SendViewSetStandbyRec(2); this->tunerChLocked = false; if( this->recView ){ ctrlCmd.SendViewExecViewApp(); } } } if( startedReserveIDList ){ startedReserveIDList->push_back(r.reserveID); } }else{ //開始できなかった ret.type = CHECK_ERR_RECSTART; } } break; case TR_REC: { //ステータス確認 DWORD status; if( r.recMode != RECMODE_VIEW && ctrlCmd.SendViewGetStatus(&status) == CMD_SUCCESS && status != VIEW_APP_ST_REC ){ //キャンセルされた? ret.type = CHECK_ERR_REC; this->tunerResetLock = true; }else if( r.startTime + r.endMargin + r.durationSecond * I64_1SEC < now ){ ret.type = CHECK_ERR_REC; ret.continueRec = false; ret.drops = 0; ret.scrambles = 0; bool isMainCtrl = true; for( int i = 0; i < 2; i++ ){ if( r.ctrlID[i] != 0 ){ if( r.recMode == RECMODE_VIEW ){ if( isMainCtrl ){ ret.type = CHECK_END; } }else{ SET_CTRL_REC_STOP_PARAM param; param.ctrlID = r.ctrlID[i]; param.saveErrLog = this->saveErrLog; SET_CTRL_REC_STOP_RES_PARAM resVal; if( ctrlCmd.SendViewStopRec(param, &resVal) != CMD_SUCCESS ){ if( isMainCtrl ){ ret.type = CHECK_ERR_RECEND; } }else if( isMainCtrl ){ ret.type = resVal.subRecFlag ? CHECK_END_END_SUBREC : r.notStartHead ? CHECK_END_NOT_START_HEAD : r.savedPgInfo == false ? CHECK_END_NOT_FIND_PF : CHECK_END; ret.recFilePath = resVal.recFilePath; ret.drops = resVal.drop; ret.scrambles = resVal.scramble; ret.epgStartTime = r.epgStartTime; ret.epgEventName = r.epgEventName; } } ctrlCmd.SendViewDeleteCtrl(r.ctrlID[i]); isMainCtrl = false; } } //録画終了に伴ってGUIキープが解除されたかもしれない this->tunerResetLock = true; }else{ //番組情報確認 if( r.savedPgInfo == false && r.recMode != RECMODE_VIEW ){ GET_EPG_PF_INFO_PARAM val; val.ONID = r.onid; val.TSID = r.tsid; val.SID = r.sid; val.pfNextFlag = FALSE; EPGDB_EVENT_INFO resVal; if( ctrlCmd.SendViewGetEventPF(&val, &resVal) == CMD_SUCCESS && resVal.StartTimeFlag && resVal.DurationFlag && ConvertI64Time(resVal.start_time) <= r.startTime + 30 * I64_1SEC && r.startTime + 30 * I64_1SEC < ConvertI64Time(resVal.start_time) + resVal.durationSec * I64_1SEC && (r.eid == 0xFFFF || r.eid == resVal.event_id) ){ //開始時間から30秒は過ぎているのでこの番組情報が録画中のもののはず r.savedPgInfo = true; r.epgStartTime = resVal.start_time; r.epgEventName = resVal.shortInfo ? resVal.shortInfo->event_name : L""; //ごく稀にAPR(改行)を含むため Replace(r.epgEventName, L"\r\n", L""); if( this->saveProgramInfo ){ for( int i = 0; i < 2; i++ ){ wstring recPath; if( r.ctrlID[i] != 0 && ctrlCmd.SendViewGetRecFilePath(r.ctrlID[i], &recPath) == CMD_SUCCESS ){ SaveProgramInfo(recPath.c_str(), resVal, r.appendPgInfo); } } } } } //まだ録画中の予約があるのでGUIキープを再設定してはいけない ngResetLock = true; } } break; } if( ret.type != 0 ){ ret.reserveID = itrRes->first; retList.push_back(ret); this->reserveMap.erase(itrRes++); }else{ itrRes++; } } //TR_IDLE->TR_READYの遷移を待つ予約を開始順に並べる std::sort(idleList.begin(), idleList.end()); //TR_IDLE->TR_READY(TR_REC)の遷移をする for( vector<pair<__int64, DWORD>>::const_iterator itrIdle = idleList.begin(); itrIdle != idleList.end(); itrIdle++ ){ map<DWORD, TUNER_RESERVE>::iterator itrRes = this->reserveMap.find(itrIdle->second); TUNER_RESERVE& r = itrRes->second; CHECK_RESULT ret; ret.type = 0; if( this->hTunerProcess == NULL ){ //チューナを起動する SET_CH_INFO initCh; initCh.ONID = r.onid; initCh.TSID = r.tsid; initCh.SID = r.sid; initCh.useSID = TRUE; initCh.useBonCh = FALSE; bool nwUdpTcp = this->recNW || r.recMode == RECMODE_VIEW; if( OpenTuner(this->recMinWake, nwUdpTcp, nwUdpTcp, true, &initCh) ){ this->tunerONID = r.onid; this->tunerTSID = r.tsid; this->tunerChLocked = true; this->tunerResetLock = false; this->tunerChChgTick = GetTickCount(); this->notifyManager.AddNotifyMsg(NOTIFY_UPDATE_PRE_REC_START, this->bonFileName); ctrlCmd.SetPipeSetting(CMD2_VIEW_CTRL_WAIT_CONNECT, CMD2_VIEW_CTRL_PIPE, this->tunerPid); r.retryOpenCount = 0; }else if( ++r.retryOpenCount >= 4 || r.retryOpenCount == 2 && CloseOtherTuner() == false ){ //試行2回→他チューナ終了成功時さらに2回→起動できなかった ret.type = CHECK_ERR_OPEN; } }else{ r.retryOpenCount = 0; } if( this->hTunerProcess && (r.startTime - r.startMargin) / I64_1SEC - READY_MARGIN < now / I64_1SEC ){ //録画開始READY_MARGIN秒前〜 //原作では録画制御作成は通常録画時60秒前、割り込み録画時15秒前だが //作成を前倒しする必要は特にないのと、チャンネル変更からEIT[p/f]取得までの時間を確保できるようこの秒数にした if( this->specialState == TR_EPGCAP ){ //EPG取得をキャンセル(遷移中断) OutputDebugString(L"epg cancel\r\n"); //CSendCtrlCmd::SendViewEpgCapStop()は送らない(即座にチューナ閉じるので意味がないため) CloseTuner(); this->specialState = TR_IDLE; break; }else if( this->specialState == TR_NWTV ){ //ネットワークモードを解除 wstring bonDriver; DWORD status; if( ctrlCmd.SendViewGetBonDrivere(&bonDriver) == CMD_SUCCESS && CompareNoCase(bonDriver, this->bonFileName) == 0 && ctrlCmd.SendViewGetStatus(&status) == CMD_SUCCESS && (status == VIEW_APP_ST_NORMAL || status == VIEW_APP_ST_ERR_CH_CHG) ){ //プロセスを引き継ぐ this->tunerONID = r.onid; this->tunerTSID = r.tsid; this->tunerChLocked = false; this->tunerResetLock = false; this->specialState = TR_IDLE; }else{ //ネットワークモード終了(遷移中断) CloseNWTV(); break; } } if( this->tunerONID != r.onid || this->tunerTSID != r.tsid ){ //チャンネル違うので、TR_IDLEでない全予約の優先度を比べる map<DWORD, TUNER_RESERVE>::const_iterator itr; for( itr = this->reserveMap.begin(); itr != this->reserveMap.end(); itr++ ){ if( itr->second.state != TR_IDLE && itr->second.effectivePriority < r.effectivePriority ){ break; } } if( itr == this->reserveMap.end() ){ //TR_IDLEでない全予約は自分よりも弱いので葬る for( itr = this->reserveMap.begin(); itr != this->reserveMap.end(); ){ if( itr->second.state != TR_IDLE ){ CHECK_RESULT retOther; retOther.type = CHECK_ERR_REC; retOther.reserveID = itr->first; retOther.continueRec = false; retOther.drops = 0; retOther.scrambles = 0; bool isMainCtrl = true; for( int i = 0; i < 2; i++ ){ if( itr->second.ctrlID[i] != 0 ){ if( itr->second.state == TR_REC ){ if( isMainCtrl ){ retOther.type = CHECK_END_NEXT_START_END; } if( itr->second.recMode != RECMODE_VIEW ){ SET_CTRL_REC_STOP_PARAM param; param.ctrlID = itr->second.ctrlID[i]; param.saveErrLog = this->saveErrLog; SET_CTRL_REC_STOP_RES_PARAM resVal; if( ctrlCmd.SendViewStopRec(param, &resVal) != CMD_SUCCESS ){ if( isMainCtrl ){ retOther.type = CHECK_ERR_RECEND; } }else if( isMainCtrl ){ retOther.recFilePath = resVal.recFilePath; retOther.drops = resVal.drop; retOther.scrambles = resVal.scramble; } } } ctrlCmd.SendViewDeleteCtrl(itr->second.ctrlID[i]); isMainCtrl = false; } } retList.push_back(retOther); this->reserveMap.erase(itr++); }else{ itr++; } } this->tunerONID = r.onid; this->tunerTSID = r.tsid; this->tunerChLocked = false; this->tunerResetLock = false; } } if( this->tunerONID == r.onid && this->tunerTSID == r.tsid ){ if( this->tunerChLocked == false ){ //チャンネル変更 SET_CH_INFO chgCh; chgCh.ONID = r.onid; chgCh.TSID = r.tsid; chgCh.SID = r.sid; chgCh.useSID = TRUE; chgCh.useBonCh = FALSE; //「予約録画待機中」 ctrlCmd.SendViewSetStandbyRec(1); if( ctrlCmd.SendViewSetCh(&chgCh) == CMD_SUCCESS ){ this->tunerChLocked = true; this->tunerResetLock = false; this->tunerChChgTick = GetTickCount(); } } if( this->tunerChLocked ){ //同一チャンネルなので録画制御を作成できる bool continueRec = false; for( map<DWORD, TUNER_RESERVE>::const_iterator itr = this->reserveMap.begin(); itr != this->reserveMap.end(); itr++ ){ if( itr->second.continueRecFlag && itr->second.state == TR_REC && itr->second.sid == r.sid && itr->second.recMode != RECMODE_VIEW && itr->second.recMode == r.recMode && itr->second.enableCaption == r.enableCaption && itr->second.enableData == r.enableData && itr->second.partialRecMode == r.partialRecMode ){ //連続録画なので、同一制御IDで録画開始されたことにする。TR_RECまで遷移するので注意 r.state = TR_REC; r.ctrlID[0] = itr->second.ctrlID[0]; r.ctrlID[1] = itr->second.ctrlID[1]; r.notStartHead = r.startTime - r.startMargin + 60 * I64_1SEC < now; r.appendPgInfo = itr->second.appendPgInfo || itr->second.savedPgInfo; r.savedPgInfo = false; //引継ぎ元を葬る CHECK_RESULT retOther; retOther.type = CHECK_ERR_REC; retOther.reserveID = itr->first; retOther.continueRec = true; retOther.drops = 0; retOther.scrambles = 0; for( int i = 0; i < 2; i++ ){ if( itr->second.ctrlID[i] != 0 ){ if( ctrlCmd.SendViewGetRecFilePath(itr->second.ctrlID[i], &retOther.recFilePath) == CMD_SUCCESS ){ retOther.type = itr->second.notStartHead ? CHECK_END_NOT_START_HEAD : itr->second.savedPgInfo == false ? CHECK_END_NOT_FIND_PF : CHECK_END; retOther.epgStartTime = itr->second.epgStartTime; retOther.epgEventName = itr->second.epgEventName; } break; } } retList.push_back(retOther); this->reserveMap.erase(itr); continueRec = true; break; } } if( continueRec == false ){ if( CreateCtrl(&r.ctrlID[0], &r.ctrlID[1], r) ){ r.state = TR_READY; }else{ //作成できなかった ret.type = CHECK_ERR_CTRL; } } } } } if( ret.type != 0 ){ ret.reserveID = itrRes->first; retList.push_back(ret); this->reserveMap.erase(itrRes); } } if( IsNeedOpenTuner() == false ){ //チューナが必要なくなった CloseTuner(); } if( this->hTunerProcess && this->specialState == TR_IDLE && this->tunerResetLock ){ if( ngResetLock == false ){ //「予約録画待機中」 ctrlCmd.SendViewSetStandbyRec(1); } this->tunerResetLock = false; } return retList; }
void CCheckRecFile::CheckFreeSpace(map<DWORD, CReserveInfo*>* chkReserve, wstring defRecFolder, map<wstring, wstring>* protectFile) { if( this->chkFolder.size() == 0 || chkReserve == NULL || defRecFolder.size() == 0 ) { return; } map<wstring, ULONGLONG> checkMap; map<wstring, MOUNT_PATH_INFO> mountMap; for( size_t i=0; i<this->chkFolder.size(); i++ ) { wstring folder = this->chkFolder[i]; transform(folder.begin(), folder.end(), folder.begin(), toupper); ChkFolderPath(folder); checkMap.insert(pair<wstring, ULONGLONG>(folder, 0)); wstring mountPath = L""; GetChkDrivePath(folder, mountPath); transform(mountPath.begin(), mountPath.end(), mountPath.begin(), toupper); ChkFolderPath(mountPath); map<wstring, MOUNT_PATH_INFO>::iterator itr; itr = mountMap.find(mountPath); if( itr != mountMap.end() ) { itr->second.folderPath.push_back(folder); } else { MOUNT_PATH_INFO item; item.totalSize = 0; item.folderPath.push_back(folder); mountMap.insert(pair<wstring, MOUNT_PATH_INFO>(mountPath, item)); } } LONGLONG now = GetNowI64Time(); map<DWORD, CReserveInfo*>::iterator itrRes; for( itrRes = chkReserve->begin(); itrRes != chkReserve->end(); itrRes++ ) { wstring chkFolder = defRecFolder; RESERVE_DATA data; itrRes->second->GetData(&data); if( data.recSetting.recMode == RECMODE_NO || data.recSetting.recMode == RECMODE_VIEW ) { continue; } if( now + 2*60*60*I64_1SEC < ConvertI64Time(data.startTime) ) { //2時間以上先 continue; } if( ConvertI64Time(data.startTime) < now ) { //録画中 continue; } if( data.recSetting.recFolderList.size() > 0 ) { //複数指定あり for( size_t i=0; i< data.recSetting.recFolderList.size(); i++ ) { chkFolder = data.recSetting.recFolderList[i].recFolder; transform(chkFolder.begin(), chkFolder.end(), chkFolder.begin(), toupper); ChkFolderPath(chkFolder); map<wstring, ULONGLONG>::iterator itr; itr = checkMap.find(chkFolder); if( itr != checkMap.end() ) { DWORD bitrate = 0; _GetBitrate(data.originalNetworkID, data.transportStreamID, data.serviceID, &bitrate); itr->second += ((ULONGLONG)(bitrate/8)*1000) * data.durationSecond; } wstring mountPath = L""; GetChkDrivePath(chkFolder, mountPath); transform(mountPath.begin(), mountPath.end(), mountPath.begin(), toupper); ChkFolderPath(mountPath); map<wstring, MOUNT_PATH_INFO>::iterator itrMount; itrMount = mountMap.find(mountPath); if( itrMount != mountMap.end() ) { DWORD bitrate = 0; _GetBitrate(data.originalNetworkID, data.transportStreamID, data.serviceID, &bitrate); itrMount->second.totalSize += ((ULONGLONG)(bitrate/8)*1000) * data.durationSecond; } } } else { //デフォルト transform(chkFolder.begin(), chkFolder.end(), chkFolder.begin(), toupper); ChkFolderPath(chkFolder); map<wstring, ULONGLONG>::iterator itr; itr = checkMap.find(chkFolder); if( itr != checkMap.end() ) { DWORD bitrate = 0; _GetBitrate(data.originalNetworkID, data.transportStreamID, data.serviceID, &bitrate); itr->second += ((ULONGLONG)(bitrate/8)*1000) * data.durationSecond; } wstring mountPath = L""; GetChkDrivePath(chkFolder, mountPath); transform(mountPath.begin(), mountPath.end(), mountPath.begin(), toupper); ChkFolderPath(mountPath); map<wstring, MOUNT_PATH_INFO>::iterator itrMount; itrMount = mountMap.find(mountPath); if( itrMount != mountMap.end() ) { DWORD bitrate = 0; _GetBitrate(data.originalNetworkID, data.transportStreamID, data.serviceID, &bitrate); itrMount->second.totalSize += ((ULONGLONG)(bitrate/8)*1000) * data.durationSecond; } } } //ドライブレベルでのチェック map<wstring, MOUNT_PATH_INFO>::iterator itrMount; for( itrMount = mountMap.begin(); itrMount != mountMap.end(); itrMount++ ) { if( itrMount->second.totalSize > 0 ) { ULARGE_INTEGER freeBytesAvailable; ULARGE_INTEGER totalNumberOfBytes; ULARGE_INTEGER totalNumberOfFreeBytes; if( _GetDiskFreeSpaceEx(itrMount->first.c_str(), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes ) == TRUE ) { ULONGLONG free = freeBytesAvailable.QuadPart; if( free > (ULONGLONG)itrMount->second.totalSize ) { continue; } map<LONGLONG, TS_FILE_INFO> tsFileList; for( size_t i=0; i<itrMount->second.folderPath.size(); i++ ) { FindTsFileList(itrMount->second.folderPath[i], &tsFileList); } while( free < (ULONGLONG)itrMount->second.totalSize ) { map<LONGLONG, TS_FILE_INFO>::iterator itrTS; itrTS = tsFileList.begin(); if( itrTS != tsFileList.end() ) { BOOL noDel = FALSE; map<wstring, wstring>::iterator itrP; itrP = protectFile->find(itrTS->second.filePath); if( itrP != protectFile->end() ) { noDel = TRUE; } if( noDel == FALSE ) { DeleteFile( itrTS->second.filePath.c_str() ); _OutputDebugString(L"★Auto Delete2 : %s", itrTS->second.filePath.c_str()); for( size_t i=0 ; i<this->delExt.size(); i++ ) { wstring delFile = L""; wstring delFileName = L""; GetFileFolder(itrTS->second.filePath, delFile); GetFileTitle(itrTS->second.filePath, delFileName); delFile += L"\\"; delFile += delFileName; delFile += this->delExt[i]; DeleteFile( delFile.c_str() ); _OutputDebugString(L"★Auto Delete2 : %s", delFile.c_str()); } free += itrTS->second.fileSize; } else { _OutputDebugString(L"★No Delete(Protected) : %s", itrTS->second.filePath.c_str()); } tsFileList.erase(itrTS); } else { break; } } } } } }
void CCheckRecFile::CheckFreeSpaceLive(RESERVE_DATA* reserve, wstring recFolder, map<wstring, wstring>* protectFile) { if( this->chkFolder.size() == 0 || reserve == NULL || recFolder.size() == 0 ) { return; } map<wstring, ULONGLONG> checkMap; for( size_t i=0; i<this->chkFolder.size(); i++ ) { checkMap.insert(pair<wstring, ULONGLONG>(this->chkFolder[i], 0)); } LONGLONG now = GetNowI64Time(); if( reserve->recSetting.recMode == RECMODE_NO || reserve->recSetting.recMode == RECMODE_VIEW ) { return; } map<wstring, ULONGLONG>::iterator itr; itr = checkMap.find(recFolder); if( itr != checkMap.end() ) { //500MB空いてるかチェック itr->second = 500*1024*1024; ULARGE_INTEGER freeBytesAvailable; ULARGE_INTEGER totalNumberOfBytes; ULARGE_INTEGER totalNumberOfFreeBytes; if( _GetDiskFreeSpaceEx(itr->first.c_str(), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes ) == TRUE ) { ULONGLONG free = freeBytesAvailable.QuadPart; if( free > itr->second ) { return; } map<LONGLONG, TS_FILE_INFO> tsFileList; FindTsFileList(itr->first, &tsFileList); while( free < itr->second ) { map<LONGLONG, TS_FILE_INFO>::iterator itrTS; itrTS = tsFileList.begin(); if( itrTS != tsFileList.end() ) { BOOL noDel = FALSE; map<wstring, wstring>::iterator itrP; itrP = protectFile->find(itrTS->second.filePath); if( itrP != protectFile->end() ) { noDel = TRUE; } if( noDel == FALSE ) { DeleteFile( itrTS->second.filePath.c_str() ); _OutputDebugString(L"★Auto Delete : %s", itrTS->second.filePath.c_str()); for( size_t i=0 ; i<this->delExt.size(); i++ ) { wstring delFile = L""; wstring delFileName = L""; GetFileFolder(itrTS->second.filePath, delFile); GetFileTitle(itrTS->second.filePath, delFileName); delFile += L"\\"; delFile += delFileName; delFile += this->delExt[i]; DeleteFile( delFile.c_str() ); _OutputDebugString(L"★Auto Delete : %s", delFile.c_str()); } free += itrTS->second.fileSize; } else { _OutputDebugString(L"★No Delete(Protected) : %s", itrTS->second.filePath.c_str()); } tsFileList.erase(itrTS); } else { break; } } } } }