Instrument Neutral Distributed Interface INDI 2.2.5
mjpegencoder.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 by Jasem Mutlaq <[email protected]>
3
4 INDI Raw Encoder
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#include "mjpegencoder.h"
24#include "indiccd.h"
25#include <cmath>
26#include <zlib.h>
27#include <jpeglib.h>
28#include <jerror.h>
29
30static void init_destination(j_compress_ptr cinfo)
31{
32 INDI_UNUSED(cinfo);
33 /* No work necessary here */
34}
35
36static boolean empty_output_buffer(j_compress_ptr cinfo)
37{
38 INDI_UNUSED(cinfo);
39 /* No work necessary here */
40 return TRUE;
41}
42
43static void term_destination(j_compress_ptr cinfo)
44{
45 INDI_UNUSED(cinfo);
46 /* no work necessary here */
47}
48
49namespace INDI
50{
51
53{
54 name = "MJPEG";
55}
56
58{
59 delete [] jpegBuffer;
60}
61
62const char *MJPEGEncoder::getDeviceName()
63{
65}
66
67bool MJPEGEncoder::upload(INDI::WidgetViewBlob *bp, const uint8_t *buffer, uint32_t nbytes, bool isCompressed)
68{
69 // We do not support compression
70 if (isCompressed)
71 {
72 LOG_ERROR("Compression is not supported in MJPEG stream.");
73 return false;
74 }
75
76 INDI_UNUSED(nbytes);
77 int bufsize = rawWidth * rawHeight * ((pixelFormat == INDI_RGB) ? 3 : 1);
78 if (bufsize != jpegBufferSize)
79 {
80 delete [] jpegBuffer;
81 jpegBuffer = new uint8_t[bufsize];
82 jpegBufferSize = bufsize;
83 }
84
85 // Scale image DOWN by this factor
86 // 640 is now selected arbitrary to test mpeg streaming performance
87 int scale = std::max(1, static_cast<int>(std::floor(rawWidth / SCALE_WIDTH)));
88 if (pixelFormat == INDI_RGB)
89 jpeg_compress_8u_rgb(buffer, rawWidth, rawHeight, rawWidth * 3, scale, jpegBuffer, &bufsize, 85);
90 else
91 jpeg_compress_8u_gray(buffer, rawWidth, rawHeight, rawWidth, scale, jpegBuffer, &bufsize, 85);
92
93 bp->setBlob(jpegBuffer);
94 bp->setBlobLen(bufsize);
95 bp->setSize(bufsize);
96 bp->setFormat(".stream_jpg");
97
98 return true;
99}
100
101/*
102FROM: https://svn.csail.mit.edu/rrg_pods/jpeg-utils/
103
104Name: jpeg-utils
105Maintainers: Albert Huang <[email protected]>
106Summary: Wrapper functions around libjpeg to simplify JPEG compression and
107 decompression with in-memory buffers.
108Description:
109 note: This is a simple enough library that you could just copy the .c
110 and .h files in to your own programs.
111
112 To use the library, link against -ljpeg-utils, or use
113 pkg-config --cflags --libs jpeg-utils
114
115Requirements:
116 libjpeg62
117
118 For faster performance, install libjpeg-turbo, an SSE-accelerated
119 library that is ABI compatible with libjpeg62.
120*/
121
122int MJPEGEncoder::jpeg_compress_8u_gray (const uint8_t * src, uint16_t width, uint16_t height, int stride, int scale,
123 uint8_t * dest,
124 int * destsize, int quality)
125{
126 struct jpeg_compress_struct cinfo;
127 struct jpeg_error_mgr jerr;
128 struct jpeg_destination_mgr jdest;
129 int out_size = *destsize;
130
131 cinfo.err = jpeg_std_error (&jerr);
132 jpeg_create_compress (&cinfo);
133 jdest.next_output_byte = dest;
134 jdest.free_in_buffer = out_size;
135 jdest.init_destination = init_destination;
136 jdest.empty_output_buffer = empty_output_buffer;
137 jdest.term_destination = term_destination;
138 cinfo.dest = &jdest;
139
140 cinfo.image_width = width;
141 cinfo.image_height = height;
142#if JPEG_LIB_VERSION >= 70
143 cinfo.scale_denom = scale;
144#else
145 INDI_UNUSED(scale);
146#endif
147 cinfo.input_components = 1;
148 cinfo.in_color_space = JCS_GRAYSCALE;
149 jpeg_set_defaults (&cinfo);
150 jpeg_set_quality (&cinfo, quality, TRUE);
151
152 jpeg_start_compress (&cinfo, TRUE);
153 while (cinfo.next_scanline < height)
154 {
155 JSAMPROW row = (JSAMPROW)(src + cinfo.next_scanline * stride);
156 jpeg_write_scanlines (&cinfo, &row, 1);
157 }
158
159 jpeg_finish_compress (&cinfo);
160 *destsize = out_size - jdest.free_in_buffer;
161 jpeg_destroy_compress (&cinfo);
162 return 0;
163}
164
165int MJPEGEncoder::jpeg_compress_8u_rgb (const uint8_t * src, uint16_t width, uint16_t height, int stride, int scale,
166 uint8_t * dest, int * destsize, int quality)
167{
168 struct jpeg_compress_struct cinfo;
169 struct jpeg_error_mgr jerr;
170 struct jpeg_destination_mgr jdest;
171 int out_size = *destsize;
172
173 cinfo.err = jpeg_std_error (&jerr);
174 jpeg_create_compress (&cinfo);
175 jdest.next_output_byte = dest;
176 jdest.free_in_buffer = out_size;
177 jdest.init_destination = init_destination;
178 jdest.empty_output_buffer = empty_output_buffer;
179 jdest.term_destination = term_destination;
180 cinfo.dest = &jdest;
181
182 cinfo.image_width = width;
183 cinfo.image_height = height;
184#if JPEG_LIB_VERSION >= 70
185 cinfo.scale_denom = scale;
186#else
187 INDI_UNUSED(scale);
188#endif
189 cinfo.input_components = 3;
190 cinfo.in_color_space = JCS_RGB;
191 jpeg_set_defaults (&cinfo);
192 jpeg_set_quality (&cinfo, quality, TRUE);
193
194 jpeg_start_compress (&cinfo, TRUE);
195 while (cinfo.next_scanline < height)
196 {
197 JSAMPROW row = (JSAMPROW)(src + cinfo.next_scanline * stride);
198 jpeg_write_scanlines (&cinfo, &row, 1);
199 }
200 jpeg_finish_compress (&cinfo);
201 *destsize = out_size - jdest.free_in_buffer;
202 jpeg_destroy_compress (&cinfo);
203 return 0;
204}
205
206}
const char * getDeviceName() const
INDI::DefaultDevice * currentDevice
INDI_PIXEL_FORMAT pixelFormat
virtual bool upload(INDI::WidgetViewBlob *bp, const uint8_t *buffer, uint32_t nbytes, bool isCompressed=false) override
@ INDI_RGB
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition indilogger.h:72
Namespace to encapsulate INDI client, drivers, and mediator classes.
void setFormat(const char *format)
#define TRUE
Definition stvdriver.c:54