1 /* This file is part of the Pangolin Project.
2 * http://github.com/stevenlovegrove/Pangolin
3 *
4 * Copyright (c) 2013 Steven Lovegrove
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 #include <pangolin/video/video_input.h>
29 #include <pangolin/video/video_output.h>
30
31 namespace pangolin
32 {
33
VideoInput()34 VideoInput::VideoInput()
35 : frame_num(0), record_frame_skip(1), record_once(false), record_continuous(false)
36 {
37 }
38
VideoInput(const std::string & input_uri,const std::string & output_uri)39 VideoInput::VideoInput(
40 const std::string& input_uri,
41 const std::string& output_uri
42 ) : frame_num(0), record_frame_skip(1), record_once(false), record_continuous(false)
43 {
44 Open(input_uri, output_uri);
45 }
46
Open(const std::string & input_uri,const std::string & output_uri)47 void VideoInput::Open(
48 const std::string& input_uri,
49 const std::string& output_uri
50 )
51 {
52 uri_input = ParseUri(input_uri);
53 uri_output = ParseUri(output_uri);
54
55 if (uri_output.scheme == "file") {
56 // Default to pango output
57 uri_output.scheme = "pango";
58 }
59
60 // Start off playing from video_src
61 video_src = OpenVideo(input_uri);
62
63 // Reset state
64 frame_num = 0;
65 videos.resize(1);
66 videos[0] = video_src.get();
67 }
68
Close()69 void VideoInput::Close()
70 {
71 // Reset this first so that recording data gets written out to disk ASAP.
72 video_recorder.reset();
73
74 video_src.reset();
75 videos.clear();
76 }
77
~VideoInput()78 VideoInput::~VideoInput()
79 {
80 Close();
81 }
82
LogFilename() const83 const std::string& VideoInput::LogFilename() const
84 {
85 return uri_output.url;
86 }
87
LogFilename()88 std::string& VideoInput::LogFilename()
89 {
90 return uri_output.url;
91 }
92
Grab(unsigned char * buffer,std::vector<Image<unsigned char>> & images,bool wait,bool newest)93 bool VideoInput::Grab( unsigned char* buffer, std::vector<Image<unsigned char> >& images, bool wait, bool newest)
94 {
95 if( !video_src ) throw VideoException("No video source open");
96
97 bool success;
98
99 if(newest) {
100 success = GrabNewest(buffer, wait);
101 }else{
102 success = GrabNext(buffer, wait);
103 }
104
105 if(success) {
106 images.clear();
107 for(size_t s=0; s < Streams().size(); ++s) {
108 images.push_back(Streams()[s].StreamImage(buffer));
109 }
110 }
111
112 return success;
113 }
114
InitialiseRecorder()115 void VideoInput::InitialiseRecorder()
116 {
117 video_recorder.reset();
118 video_recorder = OpenVideoOutput(uri_output);
119 video_recorder->SetStreams(
120 video_src->Streams(), uri_input.full_uri,
121 GetVideoDeviceProperties(video_src.get())
122 );
123 }
124
Record()125 void VideoInput::Record()
126 {
127 // Switch sub-video
128 videos.resize(1);
129 videos[0] = video_src.get();
130
131 // Initialise recorder and ensure src is started
132 InitialiseRecorder();
133 video_src->Start();
134 frame_num = 0;
135 record_continuous = true;
136 }
137
RecordOneFrame()138 void VideoInput::RecordOneFrame()
139 {
140 // Append to existing video.
141 if(!video_recorder) {
142 InitialiseRecorder();
143 }
144 record_continuous = false;
145 record_once = true;
146
147 // Switch sub-video
148 videos.resize(1);
149 videos[0] = video_src.get();
150 }
151
SizeBytes() const152 size_t VideoInput::SizeBytes() const
153 {
154 if( !video_src ) throw VideoException("No video source open");
155 return video_src->SizeBytes();
156 }
157
Streams() const158 const std::vector<StreamInfo>& VideoInput::Streams() const
159 {
160 return video_src->Streams();
161 }
162
Start()163 void VideoInput::Start()
164 {
165 video_src->Start();
166 }
167
Stop()168 void VideoInput::Stop()
169 {
170 if(IsRecording()) {
171 video_recorder.reset();
172 }else{
173 video_src->Stop();
174 }
175 }
176
GrabNext(unsigned char * image,bool wait)177 bool VideoInput::GrabNext( unsigned char* image, bool wait )
178 {
179 frame_num++;
180
181 const bool should_record = (record_continuous && !(frame_num % record_frame_skip)) || record_once;
182
183 const bool success = video_src->GrabNext(image, wait);
184
185 if( should_record && video_recorder != 0 && success) {
186 video_recorder->WriteStreams(image, GetVideoFrameProperties(video_src.get()) );
187 record_once = false;
188 }
189
190 return success;
191 }
192
GrabNewest(unsigned char * image,bool wait)193 bool VideoInput::GrabNewest( unsigned char* image, bool wait )
194 {
195 frame_num++;
196
197 const bool should_record = (record_continuous && !(frame_num % record_frame_skip)) || record_once;
198 const bool success = video_src->GrabNewest(image,wait);
199
200 if( should_record && video_recorder != 0 && success)
201 {
202 video_recorder->WriteStreams(image, GetVideoFrameProperties(video_src.get()) );
203 record_once = false;
204 }
205
206 return success;
207 }
208
SetTimelapse(size_t one_in_n_frames)209 void VideoInput::SetTimelapse(size_t one_in_n_frames)
210 {
211 record_frame_skip = one_in_n_frames;
212 }
213
IsRecording() const214 bool VideoInput::IsRecording() const
215 {
216 return video_recorder != 0;
217 }
218
219 }
220
221