Fawkes API  Fawkes Development Version
jpeg_stream_producer.cpp
1 
2 /***************************************************************************
3  * jpeg_stream_producer.cpp - Image JPEG stream producer
4  *
5  * Created: Thu Feb 06 13:04:53 2014
6  * Copyright 2006-2014 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "jpeg_stream_producer.h"
23 
24 #include <core/threading/mutex.h>
25 #include <core/threading/mutex_locker.h>
26 #include <core/threading/wait_condition.h>
27 
28 #include <fvcams/shmem.h>
29 #include <fvutils/compression/jpeg_compressor.h>
30 #include <fvutils/color/conversions.h>
31 #include <utils/time/wait.h>
32 
33 #include <cstdlib>
34 
35 using namespace firevision;
36 
37 namespace fawkes {
38 #if 0 /* just to make Emacs auto-indent happy */
39 }
40 #endif
41 
42 /** @class WebviewJpegStreamProducer::Buffer "jpeg_stream_producer.h"
43  * Image buffer passed to stream subscribers.
44  */
45 
46 /** Constructor.
47  * @param data data buffer
48  * @param size size in bytes of @p data
49  */
50 WebviewJpegStreamProducer::Buffer::Buffer(unsigned char *data, size_t size)
51  : data_(data), size_(size)
52 {
53 }
54 
55 /** Destructor. */
57 {
58  free(data_);
59 }
60 
61 
62 /** @class WebviewJpegStreamProducer::Subscriber "jpeg_stream_producer.h"
63  * JPEG stream subscriber.
64  *
65  * @fn void WebviewJpegStreamProducer::Subscriber::handle_buffer(RefPtr<Buffer> buffer) throw() = 0
66  * Notification if a new buffer is available.
67  * @param buffer new buffer, simple unref when done.
68  */
69 
70 /** Destructor. */
72 {
73 }
74 
75 /** @class WebviewJpegStreamProducer "jpeg_stream_producer.h"
76  * JPEG stream producer.
77  * This class takes an image ID and some parameters and then creates a stream
78  * of JPEG buffers that is either passed to subscribers or can be queried
79  * using the wait_for_next_frame() method.
80  * @author Tim Niemueller
81  */
82 
83 /** Constructor.
84  * @param image_id ID of the shared memory image buffer to get the input image from
85  * @param quality JPEG quality value, depends on used compressor (system default)
86  * @param fps frames per second to achieve
87  * @param vflip true to enable vertical flipping, false to disable
88  */
90  unsigned int quality, float fps, bool vflip)
91  : Thread("WebviewJpegStreamProducer", Thread::OPMODE_WAITFORWAKEUP)
92 {
95  set_name("WebviewJpegStreamProducer[%s]", image_id.c_str());
96 
97  last_buf_mutex_ = new Mutex();
98  last_buf_waitcond_ = new WaitCondition(last_buf_mutex_);
99 
100  quality_ = quality;
101  image_id_ = image_id;
102  fps_ = fps;
103  vflip_ = vflip;
104 }
105 
106 /** Destructor. */
108 {
109  delete last_buf_mutex_;
110  delete last_buf_waitcond_;
111 }
112 
113 /** Add a subscriber.
114  * @param subscriber subscriber to add, must be valid until removed or as long
115  * as this instance is valid.
116  */
117 void
119 {
120  subs_.lock();
121  subs_.push_back(subscriber);
122  subs_.sort();
123  subs_.unique();
124  subs_.unlock();
125  wakeup();
126 }
127 
128 /** Remove a subscriber.
129  * @param subscriber subscriber to remove
130  */
131 void
133 {
134  subs_.lock();
135  subs_.remove(subscriber);
136  subs_.unlock();
137 }
138 
139 
140 /** Blocks caller until new thread is available.
141  * @return newest available buffer once it becomes available
142  */
145 {
146  MutexLocker lock(last_buf_mutex_);
147  wakeup();
148  while (! last_buf_) {
149  last_buf_waitcond_->wait();
150  }
151  return last_buf_;
152 }
153 
154 void
156 {
157  cam_ = new SharedMemoryCamera(image_id_.c_str(), /* deep copy */ false);
158  jpeg_ = new JpegImageCompressor(quality_);
159  jpeg_->set_image_dimensions(cam_->pixel_width(), cam_->pixel_height());
160  jpeg_->set_compression_destination(ImageCompressor::COMP_DEST_MEM);
161  if (jpeg_->supports_vflip()) jpeg_->set_vflip(vflip_);
162 
163  in_buffer_ = malloc_buffer(YUV422_PLANAR,
164  cam_->pixel_width(), cam_->pixel_height());
165  jpeg_->set_image_buffer(YUV422_PLANAR, in_buffer_);
166 
167  long int loop_time = (long int)roundf((1. / fps_) * 1000000.);
168  timewait_ = new TimeWait(clock, loop_time);
169 }
170 
171 void
173 {
174  last_buf_mutex_->lock();
175  last_buf_.clear();
176  last_buf_mutex_->unlock();
177 
178  timewait_->mark_start();
179 
180  size_t size = jpeg_->recommended_compressed_buffer_size();
181  unsigned char *buffer = (unsigned char *)malloc(size);
182  jpeg_->set_destination_buffer(buffer, size);
183 
184  cam_->lock_for_read();
185  cam_->capture();
186  firevision::convert(cam_->colorspace(), YUV422_PLANAR,
187  cam_->buffer(), in_buffer_,
188  cam_->pixel_width(), cam_->pixel_height());
189  jpeg_->compress();
190  cam_->dispose_buffer();
191  cam_->unlock();
192 
193  RefPtr<Buffer> shared_buf(new Buffer(buffer, jpeg_->compressed_size()));
194  subs_.lock();
195 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) > 40600
196  for (auto &s : subs_) {
197 #else
199  for (si = subs_.begin(); si != subs_.end(); ++si) {
200  Subscriber *s = *si;
201 #endif
202  s->handle_buffer(shared_buf);
203  }
204  bool go_on = ! subs_.empty();
205  subs_.unlock();
206 
207  last_buf_mutex_->lock();
208  last_buf_ = shared_buf;
209  last_buf_waitcond_->wake_all();
210  last_buf_mutex_->unlock();
211 
212  if (go_on) {
213  timewait_->wait_systime();
214  wakeup();
215  }
216 }
217 
218 void
220 {
221  delete jpeg_;
222  delete cam_;
223  delete timewait_;
224  free(in_buffer_);
225 }
226 
227 } // end namespace fawkes
228 
virtual unsigned int pixel_width()
Width of image in pixels.
Definition: shmem.cpp:200
Wait until a given condition holds.
WebviewJpegStreamProducer(const std::string &image_id, unsigned int quality, float fps, bool vflip)
Constructor.
virtual void finalize()
Finalize the thread.
Fawkes library namespace.
virtual size_t compressed_size()
Get compressed size.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
void wake_all()
Wake up all waiting threads.
Mutex locking helper.
Definition: mutex_locker.h:33
virtual void compress()
Compress image.
virtual void loop()
Code to execute in the thread.
Thread class encapsulation of pthreads.
Definition: thread.h:42
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:727
Image buffer passed to stream subscribers.
Jpeg image compressor.
virtual void unlock()
Unlock buffer.
Definition: shmem.cpp:298
virtual void capture()
Capture an image.
Definition: shmem.cpp:160
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:100
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:45
virtual void dispose_buffer()
Dispose current buffer.
Definition: shmem.cpp:195
void wakeup()
Wake up thread.
Definition: thread.cpp:1000
void set_name(const char *format,...)
Set name of thread.
Definition: thread.cpp:761
virtual void handle_buffer(RefPtr< Buffer > buffer)=0
Notification if a new buffer is available.
virtual colorspace_t colorspace()
Colorspace of returned image.
Definition: shmem.cpp:213
List with a lock.
Definition: thread.h:40
Shared memory camera.
Definition: shmem.h:38
virtual void set_destination_buffer(unsigned char *buf, unsigned int buf_size)
Set destination buffer (if compressing to memory).
void set_coalesce_wakeups(bool coalesce=true)
Set wakeup coalescing.
Definition: thread.cpp:741
void wait()
Wait for the condition forever.
virtual unsigned char * buffer()
Get access to current image buffer.
Definition: shmem.cpp:172
void mark_start()
Mark start of loop.
Definition: wait.cpp:70
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:49
void remove_subscriber(Subscriber *subscriber)
Remove a subscriber.
virtual ~WebviewJpegStreamProducer()
Destructor.
void lock()
Lock this mutex.
Definition: mutex.cpp:89
virtual unsigned int pixel_height()
Height of image in pixels.
Definition: shmem.cpp:206
virtual size_t recommended_compressed_buffer_size()
Get the recommended size for the compressed buffer.
virtual void init()
Initialize the thread.
operate in wait-for-wakeup mode
Definition: thread.h:54
Mutex mutual exclusion lock.
Definition: mutex.h:32
Time wait utility.
Definition: wait.h:32
virtual void lock_for_read()
Lock image for reading.
Definition: shmem.cpp:260
void add_subscriber(Subscriber *subscriber)
Add a subscriber.
RefPtr< Buffer > wait_for_next_frame()
Blocks caller until new thread is available.