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