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