YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
MjpegCarrier.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "MjpegCarrier.h"
8#include "MjpegLogComponent.h"
9
10#include <cstdio>
11
12/*
13 On Windows, libjpeg does some slightly odd-ball stuff, including
14 unconditionally defining INT32 to be "long". This needs to
15 be worked around. Work around begins...
16 */
17#if defined(_WIN32)
18#define INT32 long // jpeg's definition
19#define QGLOBAL_H 1
20#endif
21
22#ifdef _MSC_VER
23#pragma warning (push)
24#pragma warning (disable : 4091)
25#endif
26
27extern "C" {
28#include <jpeglib.h>
29}
30
31#ifdef _MSC_VER
32#pragma warning (pop)
33#endif
34
35#if defined(_WIN32)
36#undef INT32
37#undef QGLOBAL_H
38#endif
39/*
40 work around ends.
41 */
42
43#include <yarp/sig/Image.h>
45#include <yarp/os/Name.h>
46#include <yarp/os/Bytes.h>
47#include <yarp/os/Route.h>
48
49#include "WireImage4mjpeg.h"
50
51#include <map>
52
53using namespace yarp::os;
54using namespace yarp::sig;
55
56static const std::map<int, J_COLOR_SPACE> yarpCode2Mjpeg { {VOCAB_PIXEL_MONO, JCS_GRAYSCALE},
59#ifdef LIBJPEG_TURBO_VERSION
63#else
64 };
65#endif
66
67static const std::map<int, int> yarpCode2Channels { {VOCAB_PIXEL_MONO, 1},
69 {VOCAB_PIXEL_RGB , 3},
70 {VOCAB_PIXEL_RGBA , 4},
71 {VOCAB_PIXEL_BGRA , 4},
72 {VOCAB_PIXEL_BGR , 3} };
73
74
76{
78
81 JOCTET cache[1000000]; // need to make this variable...
82};
83
85
86void send_net_data(JOCTET *data, int len, void *client) {
87 yCTrace(MJPEGCARRIER, "Send %d bytes", len);
88 auto* p = (ConnectionState *)client;
89 constexpr size_t hdr_size = 1000;
90 char hdr[hdr_size];
91 const char *brk = "\r\n";
92 std::snprintf(hdr, hdr_size, "Content-Type: image/jpeg%s\
93Content-Length: %d%s%s", brk, len, brk, brk);
95 p->os().write(hbuf);
96 Bytes buf((char *)data,len);
97 /*
98 // add corruption now and then, for testing.
99 static int ct = 0;
100 ct++;
101 if (ct==50) {
102 yCTrace(MJPEGCARRIER, "Adding corruption");
103 buf.get()[0] = 'z';
104 ct = 0;
105 }
106 */
107 p->os().write(buf);
108 std::snprintf(hdr, hdr_size, "%s--boundarydonotcross%s", brk, brk);
110 p->os().write(hbuf2);
111
112}
113
115 yCTrace(MJPEGCARRIER, "Initializing destination");
116 auto dest = (net_destination_ptr)cinfo->dest;
117 dest->buffer = &(dest->cache[0]);
118 dest->bufsize = sizeof(dest->cache);
119 dest->pub.next_output_byte = dest->buffer;
120 dest->pub.free_in_buffer = dest->bufsize;
121}
122
124 auto dest = (net_destination_ptr)cinfo->dest;
125 yCWarning(MJPEGCARRIER, "Empty buffer - PROBLEM");
126 send_net_data(dest->buffer,dest->bufsize-dest->pub.free_in_buffer,
127 cinfo->client_data);
128 dest->pub.next_output_byte = dest->buffer;
129 dest->pub.free_in_buffer = dest->bufsize;
130 return TRUE;
131}
132
134 auto dest = (net_destination_ptr)cinfo->dest;
135 yCTrace(MJPEGCARRIER, "Terminating net %d %zd", dest->bufsize,dest->pub.free_in_buffer);
136 send_net_data(dest->buffer,dest->bufsize-dest->pub.free_in_buffer,
137 cinfo->client_data);
138}
139
142
143 //ERREXIT(cinfo, JERR_BUFFER_SIZE);
144
145 /* The destination object is made permanent so that multiple JPEG images
146 * can be written to the same buffer without re-executing jpeg_net_dest.
147 */
148 if (cinfo->dest == nullptr) { /* first time for this JPEG object? */
149 cinfo->dest = (struct jpeg_destination_mgr *)
150 (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
151 sizeof(net_destination_mgr));
152 }
153
154 dest = (net_destination_ptr) cinfo->dest;
155 dest->pub.init_destination = init_net_destination;
156 dest->pub.empty_output_buffer = empty_net_output_buffer;
157 dest->pub.term_destination = term_net_destination;
158}
159
162 FlexImage *img = rep.checkForImage(writer);
163
164 if (img == nullptr) {
165 return false;
166 }
167 int w = img->width();
168 int h = img->height();
169 int row_stride = img->getRowSize();
170 auto* data = (JOCTET*)img->getRawImage();
171
173
174 struct jpeg_compress_struct cinfo;
175 struct jpeg_error_mgr jerr;
176 cinfo.err = jpeg_std_error(&jerr);
177 cinfo.client_data = &proto;
178 jpeg_create_compress(&cinfo);
179 jpeg_net_dest(&cinfo);
180 cinfo.image_width = w;
181 cinfo.image_height = h;
182#ifndef LIBJPEG_TURBO_VERSION
183 if((img->getPixelCode() == VOCAB_PIXEL_RGBA) ||
184 (img->getPixelCode() == VOCAB_PIXEL_BGRA) ||
185 (img->getPixelCode() == VOCAB_PIXEL_BGR)) {
186 yCTrace(MJPEGCARRIER, "Pixel format not supported, please compile YARP with libjpeg-turbo to support it.");
187 return false;
188 }
189#endif
190 cinfo.in_color_space = yarpCode2Mjpeg.at(img->getPixelCode());
191 cinfo.input_components = yarpCode2Channels.at(img->getPixelCode());
192 jpeg_set_defaults(&cinfo);
193 //jpeg_set_quality(&cinfo, 85, TRUE);
194 yCTrace(MJPEGCARRIER, "Starting to compress...");
195 jpeg_start_compress(&cinfo, TRUE);
196 if(!envelope.empty()) {
197 jpeg_write_marker(&cinfo, JPEG_COM, reinterpret_cast<const JOCTET*>(envelope.c_str()), envelope.length() + 1);
198 envelope.clear();
199 }
200 yCTrace(MJPEGCARRIER, "Done compressing (height %d)", cinfo.image_height);
201 while (cinfo.next_scanline < cinfo.image_height) {
202 yCTrace(MJPEGCARRIER, "Writing row %d...", cinfo.next_scanline);
203 row_pointer[0] = data + cinfo.next_scanline * row_stride;
205 }
206 jpeg_finish_compress(&cinfo);
207 jpeg_destroy_compress(&cinfo);
208
209 return true;
210}
211
213 return false;
214}
215
216
218 Name n(proto.getRoute().getCarrierName() + "://test");
219 std::string pathValue = n.getCarrierModifier("path");
220 std::string target = "GET /?action=stream\n\n";
221 if (pathValue!="") {
222 target = "GET /";
223 target += pathValue;
224 }
225 target += " HTTP/1.1\n";
226 Contact host = proto.getRoute().getToContact();
227 if (host.getHost()!="") {
228 target += "Host: ";
229 target += host.getHost();
230 target += "\r\n";
231 }
232 target += "\n";
233 Bytes b((char*)target.c_str(),target.length());
234 proto.os().write(b);
235 return true;
236}
237
239#ifdef MJPEG_AUTOCOMPRESS
240 return true;
241#else
242 return false;
243#endif
244}
@ VOCAB_PIXEL_RGBA
Definition Image.h:45
@ VOCAB_PIXEL_MONO16
Definition Image.h:43
@ VOCAB_PIXEL_BGRA
Definition Image.h:46
@ VOCAB_PIXEL_BGR
Definition Image.h:49
@ VOCAB_PIXEL_MONO
Definition Image.h:42
@ VOCAB_PIXEL_RGB
Definition Image.h:44
static const std::map< int, int > yarpCode2Channels
static boolean empty_net_output_buffer(j_compress_ptr cinfo)
static const std::map< int, J_COLOR_SPACE > yarpCode2Mjpeg
void jpeg_net_dest(j_compress_ptr cinfo)
net_destination_mgr * net_destination_ptr
static void init_net_destination(j_compress_ptr cinfo)
void send_net_data(JOCTET *data, int len, void *client)
static void term_net_destination(j_compress_ptr cinfo)
const yarp::os::LogComponent & MJPEGCARRIER()
virtual bool autoCompression() const
bool reply(yarp::os::ConnectionState &proto, yarp::os::SizedWriter &writer) override
bool write(yarp::os::ConnectionState &proto, yarp::os::SizedWriter &writer) override
Write a message.
bool sendHeader(yarp::os::ConnectionState &proto) override
Write a header appropriate to the carrier to the connection, followed by any carrier-specific data.
A mini-server for performing network communication in the background.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
A simple abstraction for a block of bytes.
Definition Bytes.h:24
The basic state of a connection - route, streams in use, etc.
OutputStream & os()
Shorthand for getOutputStream()
virtual const Route & getRoute() const =0
Get the route associated with this connection.
Represents how to reach a part of a YARP network.
Definition Contact.h:33
std::string getHost() const
Get the host name associated with this Contact for socket communication.
Definition Contact.cpp:228
Simple abstraction for a YARP port name.
Definition Name.h:18
virtual void write(char ch)
Write a single byte to the stream.
Minimal requirements for an efficient Writer.
Definition SizedWriter.h:32
Image class with user control of representation details.
Definition Image.h:363
size_t width() const
Gets width of image in pixels.
Definition Image.h:171
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition Image.h:197
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition Image.cpp:479
size_t height() const
Gets height of image in pixels.
Definition Image.h:177
virtual int getPixelCode() const
Gets pixel type identifier.
Definition Image.cpp:390
#define yCTrace(component,...)
#define yCWarning(component,...)
An interface to the operating system, including Port based communication.
struct jpeg_destination_mgr pub
JOCTET cache[1000000]