/* * Copyright (c) 2019 TOYOTA MOTOR CORPORATION * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "videoutils.h" #include #include #include #include #include #include #include #include using namespace VIDEO_UTILS; GMainLoop * mainloop = NULL; static int grabImage(void *data); static void printhelp(const char *argv0); static void mainLoopQuit(int sig); VideoUtils::VideoUtils(int device, int framerate, int wid, int hght, std::string file, std::string co) : fps(framerate), width(wid), height(hght), deviceno(device), codec(co), filename(file) { cvCapture = std::unique_ptr < cv::VideoCapture > (new cv::VideoCapture()); cvWriter = std::unique_ptr < cv::VideoWriter > (new cv::VideoWriter()); isReady = false; framecount = 0; if (cvCapture && !cvCapture->isOpened()) { if (cvCapture->open(deviceno)) { cvCapture->set(cv::CAP_PROP_FRAME_WIDTH, width); cvCapture->set(cv::CAP_PROP_FRAME_HEIGHT, height); if (cvWriter && !cvWriter->isOpened()) { isReady = openVideoWriter(); } } } } void VideoUtils::releaseSource() { if (cvCapture && cvCapture->isOpened()) { cvCapture->release(); } if (cvWriter && cvWriter->isOpened()) { cvWriter->release(); } } bool VideoUtils::openVideoWriter() { if (!cvCapture || !cvCapture->isOpened() || !cvWriter) { return false; } /* Get the size of a frame from the device. */ cv::Size framesize = cv::Size((int) cvCapture->get(cv::CAP_PROP_FRAME_WIDTH), (int) cvCapture->get(cv::CAP_PROP_FRAME_HEIGHT)); /* Get the CODEC. */ if (codec.empty() || codec.size() != 4) { codec = "MJPG"; } boost::algorithm::to_upper(codec); return cvWriter->open(filename, cv::VideoWriter::fourcc(codec.at(0), codec.at(1), codec.at(2), codec.at(3)), fps, framesize); } void VideoUtils::writeVideoFrame(const cv::UMat& f) { if (!cvWriter || !cvWriter->isOpened()) { return; } if (framecount < fps) { framecount++; return; } cv::Mat frame; f.copyTo(frame); /* Put the current time into the frame. */ int fontFace = cv::FONT_HERSHEY_SIMPLEX; double fontScale = 0.6; int baseline = 0; int thickness = 2; std::stringstream datestr; datestr << getCurrentTime(); cv::Size dateTextSize = cv::getTextSize(datestr.str(), fontFace, fontScale, thickness, &baseline); for (; fontScale > 0.1 && dateTextSize.width > frame.cols; ) { fontScale -= 0.2; dateTextSize = cv::getTextSize(datestr.str(), fontFace, fontScale, thickness, &baseline); } cv::Point dateOrg(frame.cols - dateTextSize.width, dateTextSize.height); cv::putText(frame, datestr.str(), dateOrg, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness); /* Write the frame into the log file. */ *(cvWriter.get()) << frame; } std::string VideoUtils::getCurrentTime() { time_t seconds; struct tm currenttime; if (time(&seconds) == (time_t) - 1) { return ""; } localtime_r(&seconds, ¤ttime); char timestr[] = "1900/01/01/00/00/00"; sprintf(timestr, "%04d/%02d/%02d %02d:%02d:%02d", currenttime.tm_year + 1900, currenttime.tm_mon + 1, currenttime.tm_mday, currenttime.tm_hour, currenttime.tm_min, currenttime.tm_sec); return timestr; } static int grabImage(void *data) { VideoUtils* utils = reinterpret_cast(data); if (!utils->cvCapture || !utils->cvCapture->isOpened()) { return false; } cv::UMat frame; *(utils->cvCapture.get()) >> frame; if (!frame.empty()) { /* Write the frame into the log file. */ utils->writeVideoFrame(frame); return true; } else { return false; } } static void printhelp(const char *argv0) { printf("Usage: %s [args]\n" " [-d|--device <0-5> ] set the device\n" " [-w|--width] specify the width\n" " [-h|--height] specify the height\n" " [-r]--frame rate] specify the frame rate\n" " [-c]--codec] specify the codec\n" " [-f]--folder name] specify a folder to save the video file\n", argv0); } static void mainLoopQuit(int sig) { if ((sig == SIGUSR1) && (mainloop != NULL)) { g_main_loop_quit(mainloop); } } int main(int argc, char **argv) { static int opt; int device = 0; int framerate = 30; int width = 640; int height = 480; std::string filename = "/tmp/temp.avi"; std::string codec = "MP42"; while ((opt = getopt(argc, argv, "d:w:h:r:f:c:")) != -1) { switch (opt) { case 'd': device = atoi(optarg); break; case 'w': width = atoi(optarg); break; case 'h': height = atoi(optarg); break; case 'r': framerate = atoi(optarg); break; case 'f': filename.assign(optarg); break; case 'c': codec.assign(optarg); break; default: printhelp(basename(argv[0])); return (0); } } VideoUtils utils(device, framerate, width, height, filename, codec); if (utils.isReady && framerate > 0) { void (*oldSigUsr1Handler)(int); oldSigUsr1Handler = signal(SIGUSR1, mainLoopQuit); mainloop = g_main_loop_new(NULL, FALSE); g_timeout_add(1000 / framerate, grabImage, &utils); g_main_loop_run(mainloop); g_main_loop_unref(mainloop); if (oldSigUsr1Handler != SIG_ERR) { signal(SIGUSR1, oldSigUsr1Handler); } } utils.releaseSource(); return 0; }