YARP
Yet Another Robot Platform
MjpegDecompression.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include "MjpegDecompression.h"
10 #include "MjpegLogComponent.h"
11 
12 #include <yarp/os/Log.h>
13 #include <yarp/sig/Image.h>
14 
15 #include <csetjmp>
16 #include <cstdio>
17 #include <cstring>
18 
19 #if defined(_WIN32)
20 #define INT32 long // jpeg's definition
21 #define QGLOBAL_H 1
22 #endif
23 
24 #ifdef _MSC_VER
25 #pragma warning (push)
26 #pragma warning (disable : 4091)
27 #endif
28 
29 extern "C" {
30 #include <jpeglib.h>
31 }
32 
33 #ifdef _MSC_VER
34 #pragma warning (pop)
35 #endif
36 
37 #if defined(_WIN32)
38 #undef INT32
39 #undef QGLOBAL_H
40 #endif
41 
42 
43 using namespace yarp::os;
44 using namespace yarp::sig;
45 
46 struct net_error_mgr {
47  struct jpeg_error_mgr pub;
48  jmp_buf setjmp_buffer;
49 };
50 using net_error_ptr = struct net_error_mgr*;
51 
52 using net_src_ptr = jpeg_source_mgr*;
53 
54 void init_net_source (j_decompress_ptr cinfo) {
55  //net_src_ptr src = (net_src_ptr) cinfo->src;
56 }
57 
58 
59 boolean fill_net_input_buffer (j_decompress_ptr cinfo)
60 {
61  // The whole JPEG data is expected to reside in the supplied memory
62  // buffer, so any request for more data beyond the given buffer size
63  // is treated as an error.
64  auto* mybuffer = (JOCTET *) cinfo->client_data;
65  yCWarning(MJPEGCARRIER, "JPEG data unusually large");
66  // Insert a fake EOI marker
67  mybuffer[0] = (JOCTET) 0xFF;
68  mybuffer[1] = (JOCTET) JPEG_EOI;
69  cinfo->src->next_input_byte = mybuffer;
70  cinfo->src->bytes_in_buffer = 2;
71  return TRUE;
72 }
73 
74 void net_error_exit (j_common_ptr cinfo) {
75  auto myerr = (net_error_ptr) cinfo->err;
76  (*cinfo->err->output_message) (cinfo);
77  longjmp(myerr->setjmp_buffer, 1);
78 }
79 
80 void skip_net_input_data (j_decompress_ptr cinfo, long num_bytes)
81 {
82  auto src = (net_src_ptr) cinfo->src;
83 
84  if (num_bytes > 0) {
85  while (num_bytes > (long) src->bytes_in_buffer) {
86  num_bytes -= (long) src->bytes_in_buffer;
87  (void) (*src->fill_input_buffer) (cinfo);
88  }
89  src->next_input_byte += (size_t) num_bytes;
90  src->bytes_in_buffer -= (size_t) num_bytes;
91  }
92 }
93 
94 void term_net_source (j_decompress_ptr cinfo) {
95 }
96 
97 void jpeg_net_src (j_decompress_ptr cinfo, char *buf, int buflen) {
98  net_src_ptr src;
99  if (cinfo->src == nullptr) { /* first time for this JPEG object? */
100  cinfo->src = (struct jpeg_source_mgr *)
101  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
102  sizeof(jpeg_source_mgr));
103  }
104 
105  src = (net_src_ptr) cinfo->src;
106  src->init_source = init_net_source;
107  src->fill_input_buffer = fill_net_input_buffer;
108  src->skip_input_data = skip_net_input_data;
109  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
110  src->term_source = term_net_source;
111  src->bytes_in_buffer = buflen;
112  src->next_input_byte = (JOCTET *)buf;
113 }
114 
115 
117 public:
118  bool active{false};
119  struct jpeg_decompress_struct cinfo;
120  struct net_error_mgr jerr;
121  JOCTET error_buffer[4];
122  yarp::os::InputStream::readEnvelopeCallbackType readEnvelopeCallback{nullptr};
123  void* readEnvelopeCallbackData{nullptr};
124 
126  {
127  memset(&cinfo, 0, sizeof(jpeg_decompress_struct));
128  memset(&jerr, 0, sizeof(net_error_mgr));
129  }
130 
132  void* data)
133  {
134  readEnvelopeCallback = callback;
135  readEnvelopeCallbackData = data;
136  return true;
137  }
138 
139  void init() {
140  jpeg_create_decompress(&cinfo);
141  }
142  bool decompress(const Bytes& cimg, FlexImage& img) {
143  if (!active) {
144  init();
145  active = true;
146  }
147  cinfo.client_data = &error_buffer;
148  cinfo.err = jpeg_std_error(&jerr.pub);
149  jerr.pub.error_exit = net_error_exit;
150 
151  if (setjmp(jerr.setjmp_buffer)) {
152  jpeg_finish_decompress(&cinfo);
153  return false;
154  }
155 
156  jpeg_net_src(&cinfo,(char*)cimg.get(),cimg.length());
157  jpeg_save_markers(&cinfo, JPEG_COM, 0xFFFF);
158  jpeg_read_header(&cinfo, TRUE);
159  jpeg_calc_output_dimensions(&cinfo);
160 
161  if(cinfo.jpeg_color_space == JCS_GRAYSCALE) {
163  }
164  else
165  {
167  }
168 
169  yCTrace(MJPEGCARRIER, "Got image %dx%d", cinfo.output_width, cinfo.output_height);
170  img.resize(cinfo.output_width,cinfo.output_height);
171  jpeg_start_decompress(&cinfo);
172  //int row_stride = cinfo.output_width * cinfo.output_components;
173 
174  int at = 0;
175  while (cinfo.output_scanline < cinfo.output_height) {
176  JSAMPLE *lines[1];
177  lines[0] = (JSAMPLE*)(img.getPixelAddress(0,at));
178  jpeg_read_scanlines(&cinfo, lines, 1);
179  at++;
180  }
181  if(readEnvelopeCallback && cinfo.marker_list && cinfo.marker_list->data_length > 0) {
182  Bytes envelope(reinterpret_cast<char*>(cinfo.marker_list->data), cinfo.marker_list->data_length);
183  readEnvelopeCallback(readEnvelopeCallbackData, envelope);
184  }
185  yCTrace(MJPEGCARRIER, "Read image!");
186  jpeg_finish_decompress(&cinfo);
187  return true;
188  }
189 
190  void fini() {
191  jpeg_destroy_decompress(&cinfo);
192  }
193 
195  if (active) {
196  fini();
197  active = false;
198  }
199  }
200 };
201 
202 #define HELPER(x) (*((MjpegDecompressionHelper*)(x)))
203 
205  system_resource = new MjpegDecompressionHelper;
206  yCAssert(MJPEGCARRIER, system_resource!=nullptr);
207 }
208 
210  if (system_resource!=nullptr) {
211  delete &HELPER(system_resource);
212  system_resource = nullptr;
213  }
214 }
215 
216 
218  FlexImage &image) {
219  MjpegDecompressionHelper& helper = HELPER(system_resource);
220  return helper.decompress(data, image);
221 }
222 
224  void* data)
225 {
226  MjpegDecompressionHelper& helper = HELPER(system_resource);
227  return helper.setReadEnvelopeCallback(callback, data);
228 }
229 
230 
232 #ifdef MJPEG_AUTOCOMPRESS
233  return true;
234 #else
235  return false;
236 #endif
237 }
MjpegDecompressionHelper
Definition: MjpegDecompression.cpp:116
MjpegDecompression::isAutomatic
bool isAutomatic() const
Definition: MjpegDecompression.cpp:231
yarp::sig
Signal processing.
Definition: Image.h:25
MjpegDecompressionHelper::fini
void fini()
Definition: MjpegDecompression.cpp:190
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
MjpegDecompression::~MjpegDecompression
virtual ~MjpegDecompression()
Definition: MjpegDecompression.cpp:209
init_net_source
void init_net_source(j_decompress_ptr cinfo)
Definition: MjpegDecompression.cpp:54
MjpegDecompression::decompress
bool decompress(const yarp::os::Bytes &data, yarp::sig::FlexImage &image)
Definition: MjpegDecompression.cpp:217
skip_net_input_data
void skip_net_input_data(j_decompress_ptr cinfo, long num_bytes)
Definition: MjpegDecompression.cpp:80
MjpegDecompression::MjpegDecompression
MjpegDecompression()
Definition: MjpegDecompression.cpp:204
yarp::os::InputStream::readEnvelopeCallbackType
void(* readEnvelopeCallbackType)(void *, const yarp::os::Bytes &envelope)
Callback type for setting the envelope from a message in carriers that cannot be escaped.
Definition: InputStream.h:128
Log.h
net_error_mgr
Definition: MjpegDecompression.cpp:46
net_src_ptr
jpeg_source_mgr * net_src_ptr
Definition: MjpegDecompression.cpp:52
net_error_ptr
struct net_error_mgr * net_error_ptr
Definition: MjpegDecompression.cpp:50
MjpegDecompressionHelper::MjpegDecompressionHelper
MjpegDecompressionHelper()
Definition: MjpegDecompression.cpp:125
MJPEGCARRIER
const yarp::os::LogComponent & MJPEGCARRIER()
Definition: MjpegLogComponent.cpp:16
HELPER
#define HELPER(x)
Definition: MjpegDecompression.cpp:202
yarp::sig::FlexImage
Image class with user control of representation details.
Definition: Image.h:403
MjpegDecompressionHelper::setReadEnvelopeCallback
bool setReadEnvelopeCallback(yarp::os::InputStream::readEnvelopeCallbackType callback, void *data)
Definition: MjpegDecompression.cpp:131
yarp::os::Bytes::get
const char * get() const
Definition: Bytes.cpp:30
yarp::sig::Image::getPixelAddress
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition: Image.h:227
yarp::sig::FlexImage::setPixelCode
void setPixelCode(int imgPixelCode)
Definition: Image.h:406
yarp::os::Bytes::length
size_t length() const
Definition: Bytes.cpp:25
fill_net_input_buffer
boolean fill_net_input_buffer(j_decompress_ptr cinfo)
Definition: MjpegDecompression.cpp:59
net_error_exit
void net_error_exit(j_common_ptr cinfo)
Definition: MjpegDecompression.cpp:74
yarp::sig::Image::resize
void resize(size_t imgWidth, size_t imgHeight)
Reallocate an image to be of a desired size, throwing away its current contents.
Definition: Image.cpp:466
net_error_mgr::setjmp_buffer
jmp_buf setjmp_buffer
Definition: MjpegDecompression.cpp:48
term_net_source
void term_net_source(j_decompress_ptr cinfo)
Definition: MjpegDecompression.cpp:94
jpeg_net_src
void jpeg_net_src(j_decompress_ptr cinfo, char *buf, int buflen)
Definition: MjpegDecompression.cpp:97
yarp::os::Bytes
A simple abstraction for a block of bytes.
Definition: Bytes.h:28
yCAssert
#define yCAssert(component, x)
Definition: LogComponent.h:172
Image.h
MjpegDecompression::setReadEnvelopeCallback
bool setReadEnvelopeCallback(yarp::os::InputStream::readEnvelopeCallbackType callback, void *data)
Definition: MjpegDecompression.cpp:223
VOCAB_PIXEL_MONO
@ VOCAB_PIXEL_MONO
Definition: Image.h:48
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
MjpegLogComponent.h
MjpegDecompressionHelper::init
void init()
Definition: MjpegDecompression.cpp:139
MjpegDecompressionHelper::decompress
bool decompress(const Bytes &cimg, FlexImage &img)
Definition: MjpegDecompression.cpp:142
VOCAB_PIXEL_RGB
@ VOCAB_PIXEL_RGB
Definition: Image.h:50
yCTrace
#define yCTrace(component,...)
Definition: LogComponent.h:88
MjpegDecompressionHelper::~MjpegDecompressionHelper
~MjpegDecompressionHelper()
Definition: MjpegDecompression.cpp:194
MjpegDecompression.h