Instrument Neutral Distributed Interface INDI  2.0.2
mjpegencoder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2017 by Jasem Mutlaq <mutlaqja@ikarustech.com>
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"
23 #include "stream/streammanager.h"
24 #include "indiccd.h"
25 #include <cmath>
26 #include <zlib.h>
27 #include <jpeglib.h>
28 #include <jerror.h>
29 
30 static void init_destination(j_compress_ptr cinfo)
31 {
32  INDI_UNUSED(cinfo);
33  /* No work necessary here */
34 }
35 
36 static boolean empty_output_buffer(j_compress_ptr cinfo)
37 {
38  INDI_UNUSED(cinfo);
39  /* No work necessary here */
40  return TRUE;
41 }
42 
43 static void term_destination(j_compress_ptr cinfo)
44 {
45  INDI_UNUSED(cinfo);
46  /* no work necessary here */
47 }
48 
49 namespace INDI
50 {
51 
53 {
54  name = "MJPEG";
55 }
56 
58 {
59  delete [] jpegBuffer;
60 }
61 
62 const char *MJPEGEncoder::getDeviceName()
63 {
64  return currentDevice->getDeviceName();
65 }
66 
67 bool 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 /*
102 FROM: https://svn.csail.mit.edu/rrg_pods/jpeg-utils/
103 
104 Name: jpeg-utils
105 Maintainers: Albert Huang <albert@csail.mit.edu>
106 Summary: Wrapper functions around libjpeg to simplify JPEG compression and
107  decompression with in-memory buffers.
108 Description:
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 
115 Requirements:
116  libjpeg62
117 
118  For faster performance, install libjpeg-turbo, an SSE-accelerated
119  library that is ABI compatible with libjpeg62.
120 */
121 
122 int 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 
165 int 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
Definition: basedevice.cpp:821
INDI::DefaultDevice * currentDevice
INDI_PIXEL_FORMAT pixelFormat
virtual bool upload(INDI::WidgetViewBlob *bp, const uint8_t *buffer, uint32_t nbytes, bool isCompressed=false) override
double max(void)
@ INDI_RGB
Definition: indibasetypes.h:80
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
std::vector< uint8_t > buffer
Namespace to encapsulate INDI client, drivers, and mediator classes.
void setFormat(const char *format)
#define TRUE
Definition: stvdriver.c:54