__int64 CSyoboiCalUtil::GetTimeStamp(SYSTEMTIME startTime) { SYSTEMTIME keyTime; keyTime.wYear = 1970; keyTime.wMonth = 1; keyTime.wDay = 1; //UTC+9 keyTime.wHour = 9; keyTime.wMinute = 0; keyTime.wSecond = 0; keyTime.wMilliseconds = 0; return (ConvertI64Time(startTime) - ConvertI64Time(keyTime)) / I64_1SEC; }
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 CEpgDBManager::SearchEpg( WORD ONID, WORD TSID, WORD SID, LONGLONG startTime, DWORD durationSec, EPGDB_EVENT_INFO** result ) { if( Lock() == FALSE ) return FALSE; if( _IsLoadingData() == TRUE ){ UnLock(); return FALSE; } BOOL ret = FALSE; LONGLONG key = _Create64Key(ONID, TSID, SID); map<LONGLONG, EPGDB_SERVICE_DATA*>::iterator itr; itr = this->epgMap.find(key); if( itr != this->epgMap.end() ){ map<WORD, EPGDB_EVENT_INFO*>::iterator itrInfo; for( itrInfo = itr->second->eventMap.begin(); itrInfo != itr->second->eventMap.end(); itrInfo++ ){ if( itrInfo->second->StartTimeFlag == 1 && itrInfo->second->DurationFlag == 1 ){ if( startTime == ConvertI64Time(itrInfo->second->start_time) && durationSec == itrInfo->second->durationSec ){ *result = itrInfo->second; ret = TRUE; break; } } } } UnLock(); return ret; }
DWORD CRestApiManager::GetSearchEvent(string param, HTTP_STREAM* sendParam, CEpgDBManager* epgDB) { DWORD ret = NO_ERR; map<string,string> paramMap; while(param.size()>0){ string buff; Separate(param, "&", buff, param); if(buff.size()>0){ string key; string val; Separate(buff, "=", key, val); paramMap.insert(pair<string,string>(key, val)); } } map<string,string>::iterator itr; WORD network = 0xFFFF; itr = paramMap.find("network"); if( itr != paramMap.end() ){ network = (WORD)atoi(itr->second.c_str()); } WORD days = 0; itr = paramMap.find("days"); if( itr != paramMap.end() ){ days = (WORD)atoi(itr->second.c_str()); } wstring andkey; itr = paramMap.find("andkey"); if( itr != paramMap.end() ){ string utf8; UrlDecode(itr->second.c_str(), (DWORD)itr->second.size(), utf8); UTF8toW(utf8, andkey); } wstring notkey; itr = paramMap.find("notkey"); if( itr != paramMap.end() ){ string utf8; UrlDecode(itr->second.c_str(), (DWORD)itr->second.size(), utf8); UTF8toW(utf8, notkey); } vector<DWORD> genru; itr = paramMap.find("genru"); if( itr != paramMap.end() ){ string val = itr->second; string id; while(val.size() > 0 ){ Separate(val, "-", id, val); genru.push_back((DWORD)atoi(id.c_str())); } } DWORD index = 0; itr = paramMap.find("index"); if( itr != paramMap.end() ){ index = (DWORD)atoi(itr->second.c_str()); } DWORD count = 200; itr = paramMap.find("count"); if( itr != paramMap.end() ){ count = (DWORD)atoi(itr->second.c_str()); } WORD basicOnly = 1; itr = paramMap.find("basic"); if( itr != paramMap.end() ){ basicOnly = (WORD)atoi(itr->second.c_str()); } //検索条件 EPGDB_SEARCH_KEY_INFO searchKey; searchKey.andKey = andkey; searchKey.notKey = notkey; for( size_t i=0; i<genru.size(); i++){ EPGDB_CONTENT_DATA item; item.content_nibble_level_1 = (BYTE)(genru[i]>>8); item.content_nibble_level_2 = (BYTE)(genru[i]&0x00FF); searchKey.contentList.push_back(item); } //対象サービス vector<EPGDB_SERVICE_INFO> list; if( epgDB->GetServiceList(&list) == TRUE ){ if( network != 0xFFFF ){ for( size_t i=0; i<list.size(); i++ ){ __int64 key = _Create64Key(list[i].ONID,list[i].TSID, list[i].SID); if( 0x7880 <= list[i].ONID && list[i].ONID<= 0x7FE8 ){ //地デジ if( (network & 0x0001) > 0 ){ searchKey.serviceList.push_back(key); } }else if( list[i].ONID == 0x0004 ){ //BS if( (network & 0x0002) > 0 ){ searchKey.serviceList.push_back(key); } }else if( list[i].ONID == 0x0006 || list[i].ONID == 0x0007 ){ //CS if( (network & 0x0004) > 0 ){ searchKey.serviceList.push_back(key); } }else{ //その他 if( (network & 0x0008) > 0 ){ searchKey.serviceList.push_back(key); } } } } } //対象期間 __int64 chkTime = 0; if( days > 0 ){ SYSTEMTIME now; GetLocalTime(&now); now.wHour = 0; now.wMinute = 0; now.wSecond = 0; now.wMilliseconds = 0; chkTime = ConvertI64Time(now); chkTime += days*(29*60*60*I64_1SEC); } vector<EPGDB_SEARCH_KEY_INFO> keyList; keyList.push_back(searchKey); vector<EPGDB_EVENT_INFO*> resultList; wstring xml = L""; string utf8 = ""; epgDB->SearchEpg(&keyList, &resultList); map<__int64, __int64> addID; map<__int64, __int64>::iterator itrAdd; if ( resultList.size() > 0 ){ xml += L"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><entry>"; DWORD total = 0; DWORD findCount = 0; wstring serviceinfo = L"<items>"; wstring buff; for( size_t i = 0; i<resultList.size(); i++){ if( days > 0 ){ if( chkTime < ConvertI64Time(resultList[i]->start_time)){ continue; } } if( resultList[i]->eventGroupInfo != NULL ){ BOOL find = FALSE; for( size_t j=0; j<resultList[i]->eventGroupInfo->eventDataList.size(); j++ ){ __int64 evid = _Create64Key2(resultList[i]->eventGroupInfo->eventDataList[j].original_network_id, resultList[i]->eventGroupInfo->eventDataList[j].transport_stream_id, resultList[i]->eventGroupInfo->eventDataList[j].service_id, resultList[i]->eventGroupInfo->eventDataList[j].event_id); itrAdd = addID.find(evid); if( itrAdd != addID.end() ){ find = TRUE; } } if( find == TRUE ){ continue; } } __int64 evid = _Create64Key2(resultList[i]->original_network_id, resultList[i]->transport_stream_id, resultList[i]->service_id, resultList[i]->event_id); addID.insert(pair<__int64, __int64>(evid,evid)); if( total < index ){ total++; continue; } if( index + count <= total ){ total++; continue; } total++; findCount++; EPGDB_EVENT_INFO* eventInfo = resultList[i]; serviceinfo += L"<eventinfo>"; Format(buff, L"<ONID>%d</ONID>", eventInfo->original_network_id); serviceinfo += buff; Format(buff, L"<TSID>%d</TSID>", eventInfo->transport_stream_id); serviceinfo += buff; Format(buff, L"<SID>%d</SID>", eventInfo->service_id); serviceinfo += buff; Format(buff, L"<eventID>%d</eventID>", eventInfo->event_id); serviceinfo += buff; if( eventInfo->StartTimeFlag == 1 ){ Format(buff, L"<startDate>%04d/%02d/%02d</startDate>", eventInfo->start_time.wYear, eventInfo->start_time.wMonth, eventInfo->start_time.wDay); serviceinfo += buff; Format(buff, L"<startTime>%02d:%02d:%02d</startTime>", eventInfo->start_time.wHour, eventInfo->start_time.wMinute, eventInfo->start_time.wSecond); serviceinfo += buff; Format(buff, L"<startDayOfWeek>%d</startDayOfWeek>", eventInfo->start_time.wDayOfWeek); serviceinfo += buff; } if( eventInfo->DurationFlag == 1 ){ Format(buff, L"<duration>%d</duration>", eventInfo->durationSec); serviceinfo += buff; } if( eventInfo->shortInfo != NULL ){ wstring chk = eventInfo->shortInfo->event_name; CheckXMLChar(chk); Format(buff, L"<event_name>%s</event_name>", chk.c_str()); serviceinfo += buff; chk = eventInfo->shortInfo->text_char; CheckXMLChar(chk); Format(buff, L"<event_text>%s</event_text>", chk.c_str()); serviceinfo += buff; } if( eventInfo->contentInfo != NULL ){ serviceinfo += L""; for( size_t k=0; k<eventInfo->contentInfo->nibbleList.size(); k++){ wstring nibble = L""; Format(nibble,L"<contentInfo><nibble1>%d</nibble1><nibble2>%d</nibble2></contentInfo>", eventInfo->contentInfo->nibbleList[k].content_nibble_level_1, eventInfo->contentInfo->nibbleList[k].content_nibble_level_2); serviceinfo += nibble; } } if( eventInfo->eventGroupInfo != NULL ){ for( size_t k=0; k<eventInfo->eventGroupInfo->eventDataList.size(); k++){ wstring group = L""; Format(group,L"<groupInfo><ONID>%d</ONID><TSID>%d</TSID><SID>%d</SID><eventID>%d</eventID></groupInfo>", eventInfo->eventGroupInfo->eventDataList[k].original_network_id, eventInfo->eventGroupInfo->eventDataList[k].transport_stream_id, eventInfo->eventGroupInfo->eventDataList[k].service_id, eventInfo->eventGroupInfo->eventDataList[k].event_id ); serviceinfo += group; } } Format(buff, L"<freeCAFlag>%d</freeCAFlag>", eventInfo->freeCAFlag); serviceinfo += buff; if( basicOnly == 0 ){ if( eventInfo->extInfo != NULL ){ wstring chk = eventInfo->extInfo->text_char; CheckXMLChar(chk); Format(buff, L"<event_ext_text>%s</event_ext_text>", chk.c_str()); serviceinfo += buff; } if( eventInfo->componentInfo != NULL ){ Format(buff, L"<videoInfo><stream_content>%d</stream_content><component_type>%d</component_type><component_tag>%d</component_tag><text>%s</text></videoInfo>", eventInfo->componentInfo->stream_content, eventInfo->componentInfo->component_type, eventInfo->componentInfo->component_tag, eventInfo->componentInfo->text_char.c_str() ); serviceinfo += buff; } if( eventInfo->audioInfo != NULL ){ for( size_t k=0; k<eventInfo->audioInfo->componentList.size(); k++ ){ Format(buff, L"<audioInfo><stream_content>%d</stream_content><component_type>%d</component_type><component_tag>%d</component_tag><stream_type>%d</stream_type><simulcast_group_tag>%d</simulcast_group_tag><ES_multi_lingual_flag>%d</ES_multi_lingual_flag><main_component_flag>%d</main_component_flag><quality_indicator>%d</quality_indicator><sampling_rate>%d</sampling_rate><text>%s</text></audioInfo>", eventInfo->audioInfo->componentList[k].stream_content, eventInfo->audioInfo->componentList[k].component_type, eventInfo->audioInfo->componentList[k].component_tag, eventInfo->audioInfo->componentList[k].stream_type, eventInfo->audioInfo->componentList[k].simulcast_group_tag, eventInfo->audioInfo->componentList[k].ES_multi_lingual_flag, eventInfo->audioInfo->componentList[k].main_component_flag, eventInfo->audioInfo->componentList[k].quality_indicator, eventInfo->audioInfo->componentList[k].sampling_rate, eventInfo->audioInfo->componentList[k].text_char.c_str() ); serviceinfo += buff; } } if( eventInfo->eventRelayInfo != NULL ){ for( size_t k=0; k<eventInfo->eventRelayInfo->eventDataList.size(); k++){ wstring group = L""; Format(group,L"<relayInfo><ONID>%d</ONID><TSID>%d</TSID><SID>%d</SID><eventID>%d</eventID></relayInfo>", eventInfo->eventRelayInfo->eventDataList[k].original_network_id, eventInfo->eventRelayInfo->eventDataList[k].transport_stream_id, eventInfo->eventRelayInfo->eventDataList[k].service_id, eventInfo->eventRelayInfo->eventDataList[k].event_id ); serviceinfo += group; } } } serviceinfo += L"</eventinfo>"; } serviceinfo += L"</items>"; Format(buff, L"<total>%d</total><index>%d</index><count>%d</count>", total, index, findCount); xml += buff; xml += serviceinfo; xml += L"</entry>"; }else{ xml += L"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><entry>"; xml += L"<err>EPGデータを読み込み中、または存在しません</err>"; xml += L"</entry>"; } WtoUTF8(xml, utf8); sendParam->dataSize = (DWORD)utf8.size(); sendParam->data = new BYTE[sendParam->dataSize]; memcpy(sendParam->data, utf8.c_str(), sendParam->dataSize); if( sendParam->dataSize > 0 ){ Format(sendParam->httpHeader, "HTTP/1.0 200 OK\r\nContent-Type: text/xml\r\nContent-Length: %d\r\nConnection: close\r\n\r\n", sendParam->dataSize); }else{ sendParam->httpHeader = "HTTP/1.0 400 Bad Request\r\nConnection: close\r\n\r\n"; } return ret; }
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; } } } } } }