void Retry(std::string desc) { retryStack.push_back(desc); if(retryStack.size() > maxRetries){ FlogW("Maximum number of retries reached, they were spent on:"); int repeat = 0; std::string lastStr = ""; for(auto str : retryStack){ if(lastStr == str){ repeat++; }else{ if(repeat > 0) FlogW("(repeats " << repeat << " times)"); FlogW(" * " << str); repeat = 0; } lastStr = str; } if(repeat > 0) FlogW("(repeats " << repeat << " times)"); throw VideoException(VideoException::ERetries); } }
FramePtr decodeUntilVideoFrame(){ StreamFrameMap streamFrames; streamFrames[videoStream] = Frame::CreateEmpty(); for(int i = 0; i < 100; i++){ try { bool ret = decodeFrame(streamFrames); if(!ret){ FlogW("failed to decode frame"); return false; } // throw away any resulting frames if(streamFrames[videoStream]->finished != 0) return streamFrames[videoStream]; } catch(VideoException e) { FlogW("While decoding video frame"); FlogW(e.what()); } Retry("not a video frame in decodeUntilVideoFrame()"); } FlogD("couldn't find a video frame in 100 steps"); return 0; }
int main(int argc, char** argv) { Flog_Init("Testapp"); Flog_AddTargetStream(stdout, Flog_SDebug1 |Flog_SDebug2 | Flog_SDebug3 | Flog_SVerbose | Flog_SInfo | Flog_SWarning, 1); Flog_AddTargetStream(stderr, Flog_SError | Flog_SFatal, 1); if( !Flog_AddTargetServer("localhost", Flog_DefaultPort, Flog_SAll) ){ printf("couldn't connect to server\n"); return 1; } std::string testString = "value"; FlogExpD1(testString); FlogD1("debug level " << 1); FlogD2("debug level " << 2); FlogD3("debug level " << 3); FlogD("debug default level"); FlogV("verbose"); FlogI("info"); FlogW("warning"); FlogE("error"); FlogF("fatal error"); FlogAssert(argc == 1, "Not one arugment, exiting"); FlogDie("DEATH"); return 0; }
void HandleCommand(const Command& cmd) { switch(cmd.type){ case CTPositionUpdate: if(showMessages){ FlogD("position update: " << cmd.args[0].f); } break; case CTEof: FlogD("eof"); break; case CTLogMessage: if(showMessages){ FlogD("log message (" << cmd.args[0].i << "): " << Tools::WstrToStr(cmd.args[3].str)); } break; case CTOutputPosition: FlogD("output position update: " << cmd.args[0].i << ", " << cmd.args[1].i << ", " << cmd.args[2].i << ", " << cmd.args[3].i); break; default: FlogW("unhandled command: " << (int)cmd.type); break; } }
void HandleResponse(const Command& cmd) { switch(cmd.type){ case CTGetBitmap: if(cmd.args[0].i == 1){ FlogD("got bitmap: " << cmd.args[1].i << "x" << cmd.args[2].i << " " << cmd.args[3].buf.size() << " bytes"); }else{ FlogE("failed to get a bitmap"); } break; case CTGetDimensions: FlogD("got video dimensions: success: " << cmd.args[0].i << ", " << cmd.args[1].i << " x " << cmd.args[2].i); break; default: FlogW("unhandled reponse, seq: " << cmd.seqNum << ", type: " << cmd.type); break; } }
void ProcessMessages(PlatformPtr platform, IpcMessageQueuePtr hostQueue, bool waitReady, int timeout){ for(auto& plugin : plugins){ if(!plugin.started) continue; bool done = false; while(!done){ bool ret = false; bool isRunning = true; // = false; const int period = 100; int deadSincePeriods = 0; for(int i = 0; i < timeout / period; i++){ if(i > period * 10) FlogW("waiting for slow plugin: " << plugin.executable); ret = plugin.messageQueue->GetReadBuffer([&](const std::string& type, const char* buffer, size_t size){ if(Tools::StartsWith(type, "results")){ // results message, relay to host FlogD("relaying results from: " << plugin.executable); if(hostQueue->GetWriteQueueSize() >= (int)size){ char* outBuffer = hostQueue->GetWriteBuffer(); memcpy(outBuffer, buffer, size); hostQueue->ReturnWriteBuffer(Str(type << " " << plugin.name), &outBuffer, size); }else{ hostQueue->WriteMessage(Str("error 0 " << plugin.name), "result too big for frameserver/host message queue"); FlogW("result too big for frameserver/host message queue, plugin: " << plugin.executable << " " << plugin.name); } if(!waitReady) done = true; } else if(type == "status"){ // plugin is ready for next frame // TODO actually check if the message says "ready" if(waitReady) done = true; } else if(Tools::StartsWith(type, "error")){ // error FlogD("relaying error from: " << plugin.executable); done = true; plugin.started = false; hostQueue->WriteMessage(Str(type << " " << plugin.name), buffer); } else{ // unknown FlogW("unknown message type: " << type << " from plugin: " << plugin.name); done = true; plugin.started = false; } }, period); // The deadSincePeriods counter exists to prevent a race condition where the frameserver queue read times out // because the plugin has acquired a buffer for writing a result. If the plugin then manages to terminate // before the process->IsRunning check in the frameserver, the reported result (or other message) would be ignored. // If the process has been dead the last 10 periods (1 is probably enough) we can safely assume that there are no // result messages in the queue waiting for us, and since the plugin process is dead, we can exit the loop. deadSincePeriods += plugin.process->IsRunning() ? 0 : 1; isRunning = deadSincePeriods < 10; if(ret || !isRunning) break; } if(!isRunning){ // process exited hostQueue->WriteMessage(Str("error 0 " << plugin.name), "process exited"); FlogW("process exited, plugin: " << plugin.executable << " " << plugin.name); plugin.started = false; break; } else if(!ret){ // timeout occured hostQueue->WriteMessage(Str("error 0 " << plugin.name), "timeout while processing frames"); FlogW("timeout, plugin: " << plugin.executable << " " << plugin.name); plugin.started = false; break; } } } }
bool seekInternal(double t, int depth) { ResetRetries(); emptyFrameQueue(); audioHandler->clearQueue(); int64_t firstTs = getFirstSeekTs(); double backSeek = (double)depth * 2.0f + 1.0f; int64_t minTs = tsFromTime(t - backSeek - 2.5) + firstTs; int64_t ts = tsFromTime(t - backSeek) + firstTs; int64_t maxTs = tsFromTime(t - backSeek) + firstTs; // There is no discernible way to determine if negative timestamps are allowed // (or even required) to seek to low timestamps. // On some files you must seek to negative timestamps to be able to seek to 0 // but on other files you get weird results from seeking to below 0. // So, every other try, we will allow seeking to negative timestamps. if((depth % 2) == 1){ minTs = std::max((int64_t)0, minTs); ts = std::max((int64_t)0, minTs); maxTs = std::max((int64_t)0, minTs); } FlogD("Trying to seek to minTs: " << minTs << " ts: " << ts << " maxTs: " << maxTs << " with firsTs: " << firstTs); int flags = 0; if(ts < pFormatCtx->streams[videoStream]->cur_dts) flags |= AVSEEK_FLAG_BACKWARD; int seekRet = avformat_seek_file(pFormatCtx, videoStream, minTs, ts, maxTs, flags); if(seekRet > 0){ FlogD("avformat_seek_file failed, returned " << seekRet); return false; } avcodec_flush_buffers(pCodecCtx); double newTime = t + timeFromTs(firstPts); double actualTime = skipToTs(newTime); // consider the seek failed and try again if the actual time diffs more than .5 seconds // from the desired new time. FlogD("wanted to seek to " << newTime << " and ended up at " << actualTime); bool ret = true; if(fabsf(newTime - actualTime) > .5){ if(depth < 5){ FlogD("not good enough, trying again"); return seekInternal(t, depth + 1); } else{ ret = false; FlogW("seek failed, wanted to seek to " << newTime << " and ended up at " << actualTime); } } timeHandler->SetTime(actualTime); stepIntoQueue = true; audioHandler->onSeek(); return ret; }