JeVois  1.21
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
MovieOutput.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16/*! \file */
17
19#include <jevois/Debug/Log.H>
20#include <jevois/Util/Async.H>
21
22#include <opencv2/imgproc/imgproc.hpp>
23
24#include <linux/videodev2.h> // for v4l2 pixel types
25#include <cstdlib> // for std::system()
26#include <cstdio> // for snprintf()
27#include <fstream>
28
29static char const PATHPREFIX[] = JEVOIS_ROOT_PATH "/data/movieout/";
30
31// ####################################################################################################
32jevois::MovieOutput::MovieOutput(std::string const & fn) :
33 itsBuf(1000), itsSaving(false), itsFileNum(0), itsRunning(true), itsFilebase(fn)
34{
36}
37
38// ####################################################################################################
40{
41 // Signal end of run:
42 itsRunning.store(false);
43
44 // Push an empty frame into our buffer to signal the end of video to our thread:
45 itsBuf.push(cv::Mat());
46
47 // Wait for the thread to complete:
48 LINFO("Waiting for writer thread to complete, " << itsBuf.filled_size() << " frames to go...");
49 try { itsRunFut.get(); } catch (...) { jevois::warnAndIgnoreException(); }
50 LINFO("Writer thread completed. Syncing disk...");
51 if (std::system("/bin/sync")) LERROR("Error syncing disk -- IGNORED");
52 LINFO("Video " << itsFilename << " saved.");
53}
54
55// ##############################################################################################################
57{
58 // Store the mapping so we can check frame size and format when giving out our buffer:
59 itsMapping = m;
60}
61
62// ##############################################################################################################
64{
65 if (itsSaving.load())
66 {
67 // Reset our VideoBuf using the current format:
68 itsBuffer.reset(new jevois::VideoBuf(-1, itsMapping.osize(), 0, -1));
69
70 img.width = itsMapping.ow;
71 img.height = itsMapping.oh;
72 img.fmt = itsMapping.ofmt;
73 img.fps = itsMapping.ofps;
74 img.buf = itsBuffer;
75 img.bufindex = 0;
76 }
77 else LFATAL("Cannot get() while not streaming");
78}
79
80// ##############################################################################################################
82{
83 if (itsSaving.load())
84 {
85 // Our thread will do the actual encoding:
86 if (itsBuf.filled_size() > 1000) LERROR("Image queue too large, video writer cannot keep up - DROPPING FRAME");
87 else itsBuf.push(jevois::rawimage::convertToCvBGR(img));
88
89 // Nuke our buf:
90 itsBuffer.reset();
91 }
92 else LFATAL("Aborting send() while not streaming");
93}
94
95// ##############################################################################################################
97{
98 itsSaving.store(true);
99}
100
101// ##############################################################################################################
103{
104 itsSaving.store(false);
105}
106
107// ##############################################################################################################
109{
110 itsSaving.store(false);
111
112 // Push an empty frame into our buffer to signal the end of video to our thread:
113 itsBuf.push(cv::Mat());
114
115 // Wait for the thread to empty our image buffer:
116 while (itsBuf.filled_size())
117 {
118 LINFO("Waiting for writer thread to complete, " << itsBuf.filled_size() << " frames to go...");
119 std::this_thread::sleep_for(std::chrono::milliseconds(200));
120 }
121 LINFO("Writer thread completed. Syncing disk...");
122 if (std::system("/bin/sync")) LERROR("Error syncing disk -- IGNORED");
123 LINFO("Video " << itsFilename << " saved.");
124}
125
126// ##############################################################################################################
127void jevois::MovieOutput::run() // Runs in a thread
128{
129 while (itsRunning.load())
130 {
131 // Create a VideoWriter here, since it has no close() function, this will ensure it gets destroyed and closes
132 // the movie once we stop the recording:
133 cv::VideoWriter writer;
134 int frame = 0;
135
136 while (true)
137 {
138 // Get next frame from the buffer:
139 cv::Mat im = itsBuf.pop();
140
141 // An empty image will be pushed when we are ready to close the video file:
142 if (im.empty()) break;
143
144 // Start the encoder if it is not yet running:
145 if (writer.isOpened() == false)
146 {
147 std::string const fcc = "MJPG";
148 //std::string const fcc = "MP4V";
149 int const cvfcc = cv::VideoWriter::fourcc(fcc[0], fcc[1], fcc[2], fcc[3]);
150
151 // Add path prefix if given filename is relative:
152 std::string fn = itsFilebase;
153 if (fn.empty()) LFATAL("Cannot save to an empty filename");
154 if (fn[0] != '/') fn = PATHPREFIX + fn;
155
156 // Create directory just in case it does not exist:
157 std::string const cmd = "/bin/mkdir -p " + fn.substr(0, fn.rfind('/'));
158 if (std::system(cmd.c_str())) LERROR("Error running [" << cmd << "] -- IGNORED");
159
160 // Fill in the file number; be nice and do not overwrite existing files:
161 while (true)
162 {
163 char tmp[2048];
164 std::snprintf(tmp, 2047, fn.c_str(), itsFileNum);
165 std::ifstream ifs(tmp);
166 if (ifs.is_open() == false) { itsFilename = tmp; break; }
167 ++itsFileNum;
168 }
169
170 // Open the writer:
171 if (writer.open(itsFilename, cvfcc, itsMapping.ofps, im.size(), true) == false)
172 LFATAL("Failed to open video encoder for file [" << itsFilename << ']');
173 }
174
175 // Write the frame:
176 writer << im;
177
178 // Report what is going on once in a while:
179 if ((++frame % 100) == 0) LINFO("Written " << frame << " video frames");
180 }
181
182 // Our writer runs out of scope and closes the file here.
183 ++itsFileNum;
184 }
185}
#define JEVOIS_ROOT_PATH
Root path for runtime jevois config files, videomappings.cfg, modules, etc.
Definition Config.H:73
MovieOutput(std::string const &fn)
Constructor.
Definition MovieOutput.C:32
virtual ~MovieOutput()
Virtual destructor for safe inheritance.
Definition MovieOutput.C:39
void run()
Use a thread to encode and save frames.
virtual void streamOff() override
Stop streaming.
virtual void send(RawImage const &img) override
Send an image out.
Definition MovieOutput.C:81
virtual void setFormat(VideoMapping const &m) override
Set the video format and frame rate.
Definition MovieOutput.C:56
virtual void streamOn() override
Start streaming.
Definition MovieOutput.C:96
virtual void get(RawImage &img) override
Get a pre-allocated image so that we can fill the pixel data and later send out using send()
Definition MovieOutput.C:63
std::future< void > itsRunFut
Future for our run() thread.
Definition MovieOutput.H:69
virtual void abortStream() override
Abort streaming.
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition RawImage.H:111
float fps
Programmed frames/s as given by current video mapping, may not be actual.
Definition RawImage.H:148
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition RawImage.H:147
size_t bufindex
The index of the data buffer in the kernel driver.
Definition RawImage.H:150
unsigned int width
Image width in pixels.
Definition RawImage.H:145
unsigned int height
Image height in pixels.
Definition RawImage.H:146
std::shared_ptr< VideoBuf > buf
The pixel data buffer.
Definition RawImage.H:149
A V4L2 video buffer, to be held in a shared_ptr.
Definition VideoBuf.H:30
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
Definition Log.H:230
std::string warnAndIgnoreException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
Definition Log.C:236
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
Definition Log.H:211
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition Log.H:194
cv::Mat convertToCvBGR(RawImage const &src)
Convert RawImage to OpenCV doing color conversion from any RawImage source pixel to OpenCV BGR byte.
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async(Function &&f, Args &&... args)
Async execution using a thread pool.
Simple struct to hold video mapping definitions for the processing Engine.