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 #include <fvcams/shmem.h>
28 #include <fvutils/color/conversions.h>
29 #include <fvutils/compression/jpeg_compressor.h>
30 #include <utils/time/wait.h>
31 
32 #include <cstdlib>
33 
34 using namespace firevision;
35 
36 namespace fawkes {
37 
38 /** @class WebviewJpegStreamProducer::Buffer "jpeg_stream_producer.h"
39  * Image buffer passed to stream subscribers.
40  */
41 
42 /** Constructor.
43  * @param data data buffer
44  * @param size size in bytes of @p data
45  */
46 WebviewJpegStreamProducer::Buffer::Buffer(unsigned char *data, size_t size)
47 : data_(data), size_(size)
48 {
49 }
50 
51 /** Destructor. */
53 {
54  free(data_);
55 }
56 
57 /** @class WebviewJpegStreamProducer::Subscriber "jpeg_stream_producer.h"
58  * JPEG stream subscriber.
59  *
60  * @fn void WebviewJpegStreamProducer::Subscriber::handle_buffer(std::shared_ptr<Buffer> buffer) noexcept = 0
61  * Notification if a new buffer is available.
62  * @param buffer new buffer
63  */
64 
65 /** Destructor. */
67 {
68 }
69 
70 /** @class WebviewJpegStreamProducer "jpeg_stream_producer.h"
71  * JPEG stream producer.
72  * This class takes an image ID and some parameters and then creates a stream
73  * of JPEG buffers that is either passed to subscribers or can be queried
74  * using the wait_for_next_frame() method.
75  * @author Tim Niemueller
76  */
77 
78 /** Constructor.
79  * @param image_id ID of the shared memory image buffer to get the input image from
80  * @param quality JPEG quality value, depends on used compressor (system default)
81  * @param fps frames per second to achieve
82  * @param vflip true to enable vertical flipping, false to disable
83  */
85  unsigned int quality,
86  float fps,
87  bool vflip)
88 : Thread("WebviewJpegStreamProducer", Thread::OPMODE_WAITFORWAKEUP)
89 {
92  set_name("WebviewJpegStreamProducer[%s]", image_id.c_str());
93 
94  last_buf_mutex_ = new Mutex();
95  last_buf_waitcond_ = new WaitCondition(last_buf_mutex_);
96 
97  quality_ = quality;
98  image_id_ = image_id;
99  fps_ = fps;
100  vflip_ = vflip;
101 }
102 
103 /** Destructor. */
105 {
106  delete last_buf_mutex_;
107  delete last_buf_waitcond_;
108 }
109 
110 /** Add a subscriber.
111  * @param subscriber subscriber to add, must be valid until removed or as long
112  * as this instance is valid.
113  */
114 void
116 {
117  subs_.lock();
118  subs_.push_back(subscriber);
119  subs_.sort();
120  subs_.unique();
121  subs_.unlock();
122  wakeup();
123 }
124 
125 /** Remove a subscriber.
126  * @param subscriber subscriber to remove
127  */
128 void
130 {
131  subs_.lock();
132  subs_.remove(subscriber);
133  subs_.unlock();
134 }
135 
136 /** Blocks caller until new thread is available.
137  * @return newest available buffer once it becomes available
138  */
139 std::shared_ptr<WebviewJpegStreamProducer::Buffer>
141 {
142  MutexLocker lock(last_buf_mutex_);
143  wakeup();
144  while (!last_buf_) {
145  last_buf_waitcond_->wait();
146  }
147  return last_buf_;
148 }
149 
150 void
152 {
153  cam_ = new SharedMemoryCamera(image_id_.c_str(), /* deep copy */ false);
154  jpeg_ = new JpegImageCompressor(quality_);
155  jpeg_->set_image_dimensions(cam_->pixel_width(), cam_->pixel_height());
156  jpeg_->set_compression_destination(ImageCompressor::COMP_DEST_MEM);
157  if (jpeg_->supports_vflip())
158  jpeg_->set_vflip(vflip_);
159 
160  in_buffer_ = malloc_buffer(YUV422_PLANAR, cam_->pixel_width(), cam_->pixel_height());
161  jpeg_->set_image_buffer(YUV422_PLANAR, in_buffer_);
162 
163  long int loop_time = (long int)roundf((1. / fps_) * 1000000.);
164  timewait_ = new TimeWait(clock, loop_time);
165 }
166 
167 void
169 {
170  last_buf_mutex_->lock();
171  last_buf_.reset();
172  last_buf_mutex_->unlock();
173 
174  timewait_->mark_start();
175 
176  size_t size = jpeg_->recommended_compressed_buffer_size();
177  unsigned char *buffer = (unsigned char *)malloc(size);
178  jpeg_->set_destination_buffer(buffer, size);
179 
180  cam_->lock_for_read();
181  cam_->capture();
182  firevision::convert(cam_->colorspace(),
183  YUV422_PLANAR,
184  cam_->buffer(),
185  in_buffer_,
186  cam_->pixel_width(),
187  cam_->pixel_height());
188  jpeg_->compress();
189  cam_->dispose_buffer();
190  cam_->unlock();
191 
192  std::shared_ptr<Buffer> shared_buf = std::make_shared<Buffer>(buffer, jpeg_->compressed_size());
193  subs_.lock();
194 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) > 40600
195  for (auto &s : subs_) {
196 #else
198  for (si = subs_.begin(); si != subs_.end(); ++si) {
199  Subscriber *s = *si;
200 #endif
201  s->handle_buffer(shared_buf);
202  }
203  bool go_on = !subs_.empty();
204  subs_.unlock();
205 
206  last_buf_mutex_->lock();
207  last_buf_ = shared_buf;
208  last_buf_waitcond_->wake_all();
209  last_buf_mutex_->unlock();
210 
211  if (go_on) {
212  timewait_->wait_systime();
213  wakeup();
214  }
215 }
216 
217 void
219 {
220  delete jpeg_;
221  delete cam_;
222  delete timewait_;
223  free(in_buffer_);
224 }
225 
226 } // end namespace fawkes
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
List with a lock.
Definition: lock_list.h:45
Mutex locking helper.
Definition: mutex_locker.h:34
Mutex mutual exclusion lock.
Definition: mutex.h:33
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
Thread class encapsulation of pthreads.
Definition: thread.h:46
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:716
void set_name(const char *format,...)
Set name of thread.
Definition: thread.cpp:748
void wakeup()
Wake up thread.
Definition: thread.cpp:995
@ OPMODE_WAITFORWAKEUP
operate in wait-for-wakeup mode
Definition: thread.h:58
void set_coalesce_wakeups(bool coalesce=true)
Set wakeup coalescing.
Definition: thread.cpp:729
Time wait utility.
Definition: wait.h:33
void mark_start()
Mark start of loop.
Definition: wait.cpp:68
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:96
Wait until a given condition holds.
void wait()
Wait for the condition forever.
void wake_all()
Wake up all waiting threads.
virtual void handle_buffer(std::shared_ptr< Buffer > buffer)=0
Notification if a new buffer is available.
void add_subscriber(Subscriber *subscriber)
Add a subscriber.
virtual void loop()
Code to execute in the thread.
std::shared_ptr< Buffer > wait_for_next_frame()
Blocks caller until new thread is available.
virtual void finalize()
Finalize the thread.
virtual void init()
Initialize the thread.
void remove_subscriber(Subscriber *subscriber)
Remove a subscriber.
WebviewJpegStreamProducer(const std::string &image_id, unsigned int quality, float fps, bool vflip)
Constructor.
Jpeg image compressor.
virtual void compress()
Compress image.
virtual size_t compressed_size()
Get compressed size.
virtual bool supports_vflip()
Check if image compressor can do vflip during compress.
virtual size_t recommended_compressed_buffer_size()
Get the recommended size for the compressed buffer.
virtual void set_image_buffer(colorspace_t cspace, unsigned char *buffer)
Set image buffer to compress.
virtual void set_compression_destination(ImageCompressor::CompressionDestination cd)
Set compression destination.
virtual void set_destination_buffer(unsigned char *buf, unsigned int buf_size)
Set destination buffer (if compressing to memory).
virtual void set_vflip(bool enable)
Enable or disable vflipping.
virtual void set_image_dimensions(unsigned int width, unsigned int height)
Set dimensions of image to compress.
Shared memory camera.
Definition: shmem.h:36
virtual unsigned int pixel_width()
Width of image in pixels.
Definition: shmem.cpp:193
virtual void lock_for_read()
Lock image for reading.
Definition: shmem.cpp:246
virtual colorspace_t colorspace()
Colorspace of returned image.
Definition: shmem.cpp:205
virtual void dispose_buffer()
Dispose current buffer.
Definition: shmem.cpp:188
virtual void unlock()
Unlock buffer.
Definition: shmem.cpp:280
virtual void capture()
Capture an image.
Definition: shmem.cpp:153
virtual unsigned char * buffer()
Get access to current image buffer.
Definition: shmem.cpp:165
virtual unsigned int pixel_height()
Height of image in pixels.
Definition: shmem.cpp:199
Fawkes library namespace.