#include "ReplayWrapper.h" void JUDGE_SDK_CALLBACK __examJudgeCallbackLogImpl__(int level, const char* info, int len) { ReplayWrapper::GetInstance()->replayXexamJudgeCallbackLogImpl(level, info, len); } void JUDGE_SDK_CALLBACK __examJudgeCallbackRealExamImpl__(const char* data, int len) { ReplayWrapper::GetInstance()->replayXexamJudgeCallbackRealExamImpl(data, len); } void JUDGE_SDK_CALLBACK __examJudgeCallbackPerformImpl__(const char* data, int len) { ReplayWrapper::GetInstance()->replayXexamJudgeCallbackPerformImpl(data, len); } void JUDGE_SDK_CALLBACK __examJudgeCallbackMapImageImpl__(const char* data, int len) { ReplayWrapper::GetInstance()->replayXexamJudgeCallbackMapImageImpl(data, len); } SINGLETON_IMEPLEMENT(ReplayWrapper); bool ReplayWrapper::replayInit() { return true; } void ReplayWrapper::replayUnInit() { replayReset(); examJudgeDestroy(); } void ReplayWrapper::replayReset() { m_running = false; m_pause = false; m_frameNum = 0; m_assignNum = 0; //m_trackDatas.clear(); m_kfxm.clear(); m_cond.notify_all(); __DELETE__(m_reader); if(m_thread) { if(m_thread->joinable()) { m_thread->join(); //detach线程不能被join } __DELETE__(m_thread); } } bool ReplayWrapper::replayRunning(bool running) { if(running) { if(m_filename.isEmpty()) { logwarning("m_trackfile is empty"); return false; } replayReset(); TASSERT_BOOL(nullptr == m_thread, "why not?"); m_running = true; m_thread = __KIT_NEW__(std::thread, [&, this]()->void {return replayTrackReadData();}); } else { replayReset(); IExamCar* car = FactoryExamService->getExamCar(); if(car != nullptr && car->examState() != examStateEnd) { int codeValue = examJudgeEndExam(); TASSERT(codeValue == codeSuccess, "codeValue=%s", errorCode2Name((ErrorCode)codeValue)); } //__LOOK__(""); // 日志输出未释放的内存 } return true; } bool ReplayWrapper::replayIsRunning() const { return m_running; } void ReplayWrapper::replaySetTrackFile(const QString& filename) { m_reload = true; m_filename = filename; } void ReplayWrapper::replayPause(bool pause) { m_pause = pause; } void ReplayWrapper::replayTrackReadData() { logtrace("正在加载轨迹数据,请稍等..."); if(m_reload) { m_reload = false; std::string filename = m_filename.toLocal8Bit().toStdString(); TASSERT(nullptr == m_reader, "why not?"); m_reader = __KIT_NEW__(TrackReader, filename); m_trackDatas.clear(); bool ok = m_reader->read(m_trackDatas); TASSERT(ok, ""); } while(m_running) { if(m_assignNum != 0 && m_frameNum < m_assignNum) { int cpuCount = QThread::idealThreadCount(); int ms = 20.0 / (cpuCount / 8.0); //8核CPU的每20毫秒执行快进一帧也就是每秒50帧 while(m_frameNum != m_assignNum) { if(!replayTrackReadStep(ms)) //20 { break; } } m_assignNum = 0; continue; } if(m_pause) { sdk_msleep(100); continue; } if(!replayTrackReadStep(m_playSpeedMs)) { break; } } //int codeValue = examJudgeEndExam(); //TASSERT(codeValue == codeSuccess, ""); loginfo("the track over."); emit updateNextDoing(); } bool ReplayWrapper::replayTrackReadStep(int playSpeed) { if(!m_running) return false; TTrackData::Ptr data = nullptr; //if(!m_reader->read(data)) if(!replayRead(data)) { //sdk_msleep(100); logwarning("read track data over"); return false; } switch(data->type) { case TTrackTypeInitExam: { replayTrackTypeInitExam(data); }break; case TTrackTypeBeginExam: { replayTrackTypeBeginExam(data); }break; case TTrackTypeRealExam: { replayTrackTypeRealExam(data); std::unique_lock lk(m_mt); std::cv_status s = m_cond.wait_for(lk, std::chrono::milliseconds(playSpeed)); if(std::cv_status::timeout == s) { } //replayMapTrackImage(); }break; case TTrackTypeArtificialMark: { replayTrackTypeArtificialMark(data); }break; case TTrackTypeArtificialItem: { replayTrackTypeArtificialItem(data); }break; case TTrackTypeSoundEnd: { replayTrackTypeSoundEnd(data); }break; default: TASSERT(false, ""); return false; } return true; } void ReplayWrapper::replayTrackTypeInitExam(const TTrackData::Ptr& data) { { std::string strInit(data->data); XParser parser; TInitInfo info; if(!parser.parseInitExam(strInit, &info)) { logerror("replayTrackTypeInitExam parseInitExam error."); return; } //if(!m_carInfo.kchp.empty()) //{ // if(m_carInfo.kchp == info.kchp) // { // loginfo("replayTrackTypeInitExam same car."); // return; // } // else // { // //如果不是同一辆车,要重新走初始化流程 // examJudgeDestroy(); // } //} int codeValue = codeSuccess; //static bool s_init = false; //if(!s_init) //{ // s_init = true; //} //================================================ examJudgeDestroy(); //__LOOK__(""); m_carInfo = info; codeValue = examJudgeInit(strInit.c_str(), strInit.length()); if(codeValue == errorInitAlready) { logwarning("init errorInitAlready codeValue=%d", codeValue); return; } else if(codeValue != codeSuccess) { logerror("init error codeValue=%d", codeValue); return; } //================================================ codeValue = examJudgeSetRealExamCallback(__examJudgeCallbackRealExamImpl__); TASSERT_VOID(codeValue == codeSuccess, ""); codeValue = examJudgeSetPerformCallback(__examJudgeCallbackPerformImpl__); TASSERT_VOID(codeValue == codeSuccess, ""); codeValue = examJudgeMapImageSetCallback(__examJudgeCallbackMapImageImpl__); TASSERT_VOID(codeValue == codeSuccess, ""); codeValue = examJudgeMapSetParam(m_width, m_height); TASSERT_VOID(codeValue == codeSuccess, ""); codeValue = examJudgeMapSetScaling(m_scaling); TASSERT_VOID(codeValue == codeSuccess, ""); codeValue = examJudgeMapSetDrawing(true); TASSERT_VOID(codeValue == codeSuccess, ""); } { QString org = QString::fromUtf8(data->data.c_str()); emit updateDataInitExam(org); } } void ReplayWrapper::replayTrackTypeBeginExam(const TTrackData::Ptr& data) { std::string strStu(data->data); XParser parser; TStuInfo info; if(!parser.parseBeginExam(strStu, info)) { logerror("replayTrackTypeInitExam parseInitExam error."); return; } m_stuInfo = info; { QString org = QString::fromUtf8(data->data.c_str()); emit updateDataBeginExam(org); } { Json::Value root; std::string strBegin(data->data); Tools::fromJson(strBegin, root); root["replay"] = m_replay ? 1 : 0; //root["track"] = ""; //要生成的轨迹文件 空字符串("")不生成 strBegin = Tools::toJson(root); ErrorCode codeValue = (ErrorCode)examJudgeBeginExam(strBegin.c_str(), strBegin.length()); TASSERT(codeValue == codeSuccess || codeValue == errorBeginNotQual, ""); } } void ReplayWrapper::replayTrackTypeRealExam(const TTrackData::Ptr& data) { { std::string strReal(data->data); int codeValue = examJudgeRealExam(strReal.c_str(), strReal.length()); TASSERT(codeValue == codeSuccess, ""); } { QString org = QString::fromUtf8(data->data.c_str()); emit updateDataRealExam(org); } { //m_frameNum++; //前2条数据是初始化和从0开始的 emit updateDataFrameNum(m_frameNum, m_trackDatas.size()); } } void ReplayWrapper::replayTrackTypeArtificialMark(const TTrackData::Ptr& data) { Json::Value root; bool ok = Tools::fromJson(data->data, root); TASSERT(ok, ""); int itemno = root["itemno"].asInt(); std::string serial = root["serial"].asString(); int codeValue = examJudgeArtificialMark(itemno, serial.c_str()); TASSERT(codeValue == codeSuccess, ""); { QString serialCode = QString::fromUtf8(serial.c_str()); emit updateDataArtificialMark(itemno, serialCode); } } void ReplayWrapper::replayTrackTypeArtificialItem(const TTrackData::Ptr& data) { Json::Value root; bool ok = Tools::fromJson(data->data, root); TASSERT(ok, ""); int itemno = root["itemno"].asInt(); int type = root["type"].asInt(); int codeValue = examJudgeArtificialItem(itemno, type); //TASSERT(codeValue == codeSuccess, ""); if(codeValue != codeSuccess) { logerror("examJudgeArtificialItem error %s", errorCode2Name((ErrorCode)codeValue)); } { emit updateDataArtificialItem(itemno, type); } } void ReplayWrapper::replayTrackTypeSoundEnd(const TTrackData::Ptr &data) { //return; //240709 Json::Value root; bool ok = Tools::fromJson(data->data, root); TASSERT(ok, ""); int itemno = root["itemno"].asInt(); std::string code = root["code"].asString(); int type = root["type"].asInt(); int codeValue = examJudgeSoundEnd(itemno, code.c_str(), type); //TASSERT(codeValue == codeSuccess, ""); if(codeValue != codeSuccess) { logerror("examJudgeSoundEnd error %s", errorCode2Name((ErrorCode)codeValue)); } { QString soundCode = QString::fromUtf8(code.c_str()); emit updateDataSoundEnd(itemno, soundCode, type); } } void ReplayWrapper::replayXexamJudgeCallbackLogImpl(int level, const char* info, int len) { //QString unicode = replay::converAnyToString(QByteArray(info, len)); emit updateDataLog(level, QByteArray(info, len)); //QString::fromLocal8Bit(info, len) } void ReplayWrapper::replayXexamJudgeCallbackRealExamImpl(const char* data, int len) { emit updateDataCallbackRealExam(QString::fromLocal8Bit(data, len)); } void ReplayWrapper::replayXexamJudgeCallbackPerformImpl(const char* data, int len) { emit updateDataCallbackPerform(QString::fromLocal8Bit(data, len)); } void ReplayWrapper::replayXexamJudgeCallbackMapImageImpl(const char* data, int len) { TASSERT(len == m_width * m_height * 4, ""); QImage img((const uchar*)data, m_width, m_height, QImage::Format_RGBA8888); emit updateDataImage(img); } void ReplayWrapper::replayMapTrackImage() { //QPixmap::fromImage(img); QImage img((const uchar*)examJudgeMapImage(), m_width, m_height, QImage::Format_RGBA8888); emit updateDataImage(img); } int ReplayWrapper::replayTrackDataSize() { return m_trackDatas.size(); } ExamSubject ReplayWrapper::replayExamSubject() { return (ExamSubject)m_carInfo.kskm; } ExamCarType ReplayWrapper::replayExamCarType() { return name2ExamCarType(m_carInfo.kscx.c_str()); } const TInitInfo& ReplayWrapper::replayCarInitInfo() { return m_carInfo; } const TStuInfo& ReplayWrapper::replayStuInfo() { return m_stuInfo; } void ReplayWrapper::replayRetrogress() { m_frameNum--; m_frameNum--;//replayTrackReadStep()会++所以要两次--才能倒退到上一针 //前两帧一个是初始化考试,一个是开始考试,要过滤掉 if(m_frameNum < 2) m_frameNum = 2; replayTrackReadStep(); } void ReplayWrapper::replaySetSlider(int value) { m_slider = value; double percent = m_slider / 100.0; m_frameNum = percent * m_trackDatas.size(); //前两帧一个是初始化考试,一个是开始考试,要过滤掉 if(m_frameNum < 2) m_frameNum = 2; replayTrackReadStep(); } bool ReplayWrapper::replayRead(TTrackData::Ptr& data) { if(m_frameNum >= 0 && m_frameNum < (int)m_trackDatas.size()) { data = m_trackDatas[m_frameNum]; m_frameNum++; return true; } return false; } bool ReplayWrapper::replayIsPause() const { return m_pause; } void ReplayWrapper::replaySetSize(int width, int height) { m_width = width; m_height = height; } void ReplayWrapper::replaySetScaling(int scaling) { m_scaling = scaling; if(m_running) { examJudgeMapSetScaling(m_scaling); replayMapTrackImage(); } } void ReplayWrapper::replaySetPlaySpeed(int playSpeed) { m_playSpeed = playSpeed; m_playSpeedMs = double(SECOND) / m_playSpeed; m_cond.notify_all(); } int ReplayWrapper::replayStretchScaling(bool plus) { m_scaling += (plus ? 10 : -10); if(m_scaling <= 0) { m_scaling = 1; } if(m_scaling > 5000) { m_scaling = 5000; } if(m_running) { examJudgeMapSetScaling(m_scaling); replayMapTrackImage(); } return m_scaling; } int ReplayWrapper::replayStretchPlaySpeed(bool plus) { if(m_playSpeed < 10) { m_playSpeed += (plus ? 1 : -1); } else { m_playSpeed *= (plus ? 2 : 0.5); if(!plus && m_playSpeed < 10) { m_playSpeed = 9; } } if(m_playSpeed <= 0) { m_playSpeed = 1; //最慢每秒1幀 } if(m_playSpeed > 200) { m_playSpeed = 200; //最快每秒100幀 } m_playSpeedMs = double(SECOND) / m_playSpeed; return m_playSpeed; } void ReplayWrapper::replaySetAssignNum(int num) { m_assignNum = num; } void ReplayWrapper::replayReplay(bool replay) { m_replay = replay; } void ReplayWrapper::replayItemMarkPush(ExamItemCode itemNo, const TKfXm& kf) { //m_kfxm.push_back(kf); TKfXms& kfxm = m_kfxm[itemNo]; kfxm.push_back(kf); } int ReplayWrapper::replayItemMarkSize() const { return m_kfxm.size(); } bool ReplayWrapper::replayItemMarkHas(ExamItemCode itemNo) const { //for(size_t i = 0; i < m_kfxm.size(); i++) //{ // if(itemNo == m_kfxm[i].xmdm) // { // return true; // } //} //return false; auto it = m_kfxm.find(itemNo); return it != m_kfxm.end() ? it->second.size() > 0 : false; } void ReplayWrapper::replaySetLogLevel(LogLvType lv) { m_logLv = lv; int codeValue = examJudgeSetLogCallback(m_logLv, __examJudgeCallbackLogImpl__); TASSERT_VOID(codeValue == codeSuccess, ""); }