static int threadVideoSelectLoop(Runtime* _runtime, CodecEngine* _ce, V4L2Input* _v4l2, FBOutput* _fb) { int res; int maxFd = 0; fd_set fdsIn; static const struct timespec s_selectTimeout = { .tv_sec=1, .tv_nsec=0 }; if (_runtime == NULL || _ce == NULL || _v4l2 == NULL || _fb == NULL) return EINVAL; FD_ZERO(&fdsIn); FD_SET(_v4l2->m_fd, &fdsIn); if (maxFd < _v4l2->m_fd) maxFd = _v4l2->m_fd; if ((res = pselect(maxFd+1, &fdsIn, NULL, NULL, &s_selectTimeout, NULL)) < 0) { res = errno; fprintf(stderr, "pselect() failed: %d\n", res); return res; } if (!FD_ISSET(_v4l2->m_fd, &fdsIn)) { fprintf(stderr, "pselect() did not select V4L2\n"); return EBUSY; } const void* frameSrcPtr; size_t frameSrcSize; size_t frameSrcIndex; if ((res = v4l2InputGetFrame(_v4l2, &frameSrcPtr, &frameSrcSize, &frameSrcIndex)) != 0) { fprintf(stderr, "v4l2InputGetFrame() failed: %d\n", res); return res; } void* frameDstPtr; size_t frameDstSize; if ((res = fbOutputGetFrame(_fb, &frameDstPtr, &frameDstSize)) != 0) { fprintf(stderr, "fbOutputGetFrame() failed: %d\n", res); return res; } TargetDetectParams targetParams; TargetLocation targetLocation; if ((res = runtimeGetTargetDetectParams(_runtime, &targetParams)) != 0) { fprintf(stderr, "runtimeGetTargetDetectParams() failed: %d\n", res); return res; } size_t frameDstUsed = frameDstSize; if ((res = codecEngineTranscodeFrame(_ce, frameSrcPtr, frameSrcSize, frameDstPtr, frameDstSize, &frameDstUsed, &targetParams, &targetLocation)) != 0) { fprintf(stderr, "codecEngineTranscodeFrame(%p[%zu] -> %p[%zu]) failed: %d\n", frameSrcPtr, frameSrcSize, frameDstPtr, frameDstSize, res); return res; } if ((res = fbOutputPutFrame(_fb)) != 0) { fprintf(stderr, "fbOutputPutFrame() failed: %d\n", res); return res; } if ((res = v4l2InputPutFrame(_v4l2, frameSrcIndex)) != 0) { fprintf(stderr, "v4l2InputPutFrame() failed: %d\n", res); return res; } if ((res = runtimeSetTargetLocation(_runtime, &targetLocation)) != 0) { fprintf(stderr, "runtimeSetTargetLocation() failed: %d\n", res); return res; } return 0; } void* threadVideo(void* _arg) { int res = 0; intptr_t exit_code = 0; Runtime* runtime = (Runtime*)_arg; CodecEngine* ce; V4L2Input* v4l2; FBOutput* fb; struct timespec last_fps_report_time; if (runtime == NULL) { exit_code = EINVAL; goto exit; } if ( (ce = runtimeModCodecEngine(runtime)) == NULL || (v4l2 = runtimeModV4L2Input(runtime)) == NULL || (fb = runtimeModFBOutput(runtime)) == NULL) { exit_code = EINVAL; goto exit; } if ((res = codecEngineOpen(ce, runtimeCfgCodecEngine(runtime))) != 0) { fprintf(stderr, "codecEngineOpen() failed: %d\n", res); exit_code = res; goto exit; } if ((res = v4l2InputOpen(v4l2, runtimeCfgV4L2Input(runtime))) != 0) { fprintf(stderr, "v4l2InputOpen() failed: %d\n", res); exit_code = res; goto exit_ce_close; } if ((res = fbOutputOpen(fb, runtimeCfgFBOutput(runtime))) != 0) { fprintf(stderr, "fbOutputOpen() failed: %d\n", res); exit_code = res; goto exit_v4l2_close; } ImageDescription srcImageDesc; ImageDescription dstImageDesc; if ((res = v4l2InputGetFormat(v4l2, &srcImageDesc)) != 0) { fprintf(stderr, "v4l2InputGetFormat() failed: %d\n", res); exit_code = res; goto exit_fb_close; } if ((res = fbOutputGetFormat(fb, &dstImageDesc)) != 0) { fprintf(stderr, "fbOutputGetFormat() failed: %d\n", res); exit_code = res; goto exit_fb_close; } if ((res = codecEngineStart(ce, runtimeCfgCodecEngine(runtime), &srcImageDesc, &dstImageDesc)) != 0) { fprintf(stderr, "codecEngineStart() failed: %d\n", res); exit_code = res; goto exit_fb_close; } if ((res = v4l2InputStart(v4l2)) != 0) { fprintf(stderr, "v4l2InputStart() failed: %d\n", res); exit_code = res; goto exit_ce_stop; } if ((res = fbOutputStart(fb)) != 0) { fprintf(stderr, "fbOutputStart() failed: %d\n", res); exit_code = res; goto exit_v4l2_stop; } if ((res = clock_gettime(CLOCK_MONOTONIC, &last_fps_report_time)) != 0) { fprintf(stderr, "clock_gettime(CLOCK_MONOTONIC) failed: %d\n", errno); exit_code = res; goto exit_fb_stop; } printf("Entering video thread loop\n"); while (!runtimeGetTerminate(runtime)) { struct timespec now; long long last_fps_report_elapsed_ms; if ((res = clock_gettime(CLOCK_MONOTONIC, &now)) != 0) { fprintf(stderr, "clock_gettime(CLOCK_MONOTONIC) failed: %d\n", errno); exit_code = res; goto exit_fb_stop; } last_fps_report_elapsed_ms = (now.tv_sec - last_fps_report_time.tv_sec )*1000 + (now.tv_nsec - last_fps_report_time.tv_nsec)/1000000; if (last_fps_report_elapsed_ms >= 10*1000) { last_fps_report_time.tv_sec += 10; if ((res = codecEngineReportLoad(ce, last_fps_report_elapsed_ms)) != 0) fprintf(stderr, "codecEngineReportLoad() failed: %d\n", res); if ((res = v4l2InputReportFPS(v4l2, last_fps_report_elapsed_ms)) != 0) fprintf(stderr, "v4l2InputReportFPS() failed: %d\n", res); } if ((res = threadVideoSelectLoop(runtime, ce, v4l2, fb)) != 0) { fprintf(stderr, "threadVideoSelectLoop() failed: %d\n", res); exit_code = res; goto exit_fb_stop; } } printf("Left video thread loop\n"); exit_fb_stop: if ((res = fbOutputStop(fb)) != 0) fprintf(stderr, "fbOutputStop() failed: %d\n", res); exit_v4l2_stop: if ((res = v4l2InputStop(v4l2)) != 0) fprintf(stderr, "v4l2InputStop() failed: %d\n", res); exit_ce_stop: if ((res = codecEngineStop(ce)) != 0) fprintf(stderr, "codecEngineStop() failed: %d\n", res); exit_fb_close: if ((res = fbOutputClose(fb)) != 0) fprintf(stderr, "fbOutputClose() failed: %d\n", res); exit_v4l2_close: if ((res = v4l2InputClose(v4l2)) != 0) fprintf(stderr, "v4l2InputClose() failed: %d\n", res); exit_ce_close: if ((res = codecEngineClose(ce)) != 0) fprintf(stderr, "codecEngineClose() failed: %d\n", res); exit: runtimeSetTerminate(runtime); return (void*)exit_code; }
// Video thread void* threadVideo(void* _arg) { intptr_t exit_code = 0; Runtime* runtime = (Runtime*)_arg; CodecEngine* ce; FBOutput* fb; int res = 0; struct timespec last_fps_report_time; ImageDescription srcImageDesc; ImageDescription dstImageDesc; if (runtime == NULL) { exit_code = EINVAL; goto exit; } if ((ce = runtimeModCodecEngine(runtime)) == NULL || (fb = runtimeModFBOutput(runtime)) == NULL) { exit_code = EINVAL; goto exit; } if ((res = codecEngineOpen(ce, runtimeCfgCodecEngine(runtime))) != 0) { fprintf(stderr, "codecEngineOpen() failed: %d\n", res); exit_code = res; goto exit; } if ((res = fbOutputOpen(fb, runtimeCfgFBOutput(runtime))) != 0) { fprintf(stderr, "fbOutputOpen() failed: %d\n", res); exit_code = res; goto exit_ce_close; } if ((res = fbOutputGetFormat(fb, &dstImageDesc)) != 0) { fprintf(stderr, "fbOutputGetFormat() failed: %d\n", res); exit_code = res; goto exit_fb_close; } memcpy(&srcImageDesc, &dstImageDesc, sizeof(srcImageDesc)); srcImageDesc.m_format = ImageSourceFormat; srcImageDesc.m_imageSize = FrameSourceSize; if ((res = codecEngineStart(ce, runtimeCfgCodecEngine(runtime), &srcImageDesc, &dstImageDesc)) != 0) { fprintf(stderr, "codecEngineStart() failed: %d\n", res); exit_code = res; goto exit_fb_close; } if ((res = fbOutputStart(fb)) != 0) { fprintf(stderr, "fbOutputStart() failed: %d\n", res); exit_code = res; goto exit_ce_close; } if ((res = clock_gettime(CLOCK_MONOTONIC, &last_fps_report_time)) != 0) { fprintf(stderr, "clock_gettime(CLOCK_MONOTONIC) failed: %d\n", errno); exit_code = res; goto exit_fb_stop; } printf("Open default soundcard\n"); init_soundcard(); printf("Entering video thread loop\n"); while (!runtimeGetTerminate(runtime)) { struct timespec now; long long last_fps_report_elapsed_ms; if ((res = clock_gettime(CLOCK_MONOTONIC, &now)) != 0) { fprintf(stderr, "clock_gettime(CLOCK_MONOTONIC) failed: %d\n", errno); exit_code = res; goto exit_fb_stop; } last_fps_report_elapsed_ms = (now.tv_sec - last_fps_report_time.tv_sec )*1000 + (now.tv_nsec - last_fps_report_time.tv_nsec)/1000000; if (last_fps_report_elapsed_ms >= 10*1000) { last_fps_report_time.tv_sec += 10; if ((res = codecEngineReportLoad(ce, last_fps_report_elapsed_ms)) != 0) fprintf(stderr, "codecEngineReportLoad() failed: %d\n", res); if ((res = InputReportFPS(last_fps_report_elapsed_ms)) != 0) fprintf(stderr, "InputReportFPS() failed: %d\n", res); } if ((res = threadVideoSelectLoop(runtime, ce, fb)) != 0) { fprintf(stderr, "threadVideoSelectLoop() failed: %d\n", res); exit_code = res; goto exit_fb_stop; } } printf("Left video thread loop\n"); exit_fb_stop: if ((res = fbOutputStop(fb)) != 0) fprintf(stderr, "fbOutputStop() failed: %d\n", res); exit_ce_stop: if ((res = codecEngineStop(ce)) != 0) fprintf(stderr, "codecEngineStop() failed: %d\n", res); exit_fb_close: if ((res = fbOutputClose(fb)) != 0) fprintf(stderr, "fbOutputClose() failed: %d\n", res); exit_ce_close: if ((res = codecEngineClose(ce)) != 0) fprintf(stderr, "codecEngineClose() failed: %d\n", res); exit: runtimeSetTerminate(runtime); printf("Close default soundcard\n"); close_soundcard(); return (void*)exit_code; }