Fix some problems reported by Valgrind
[jpcrr.git] / streamtools / resize.cpp
blob29cced141b01a4f72ca2177f811c190caca98f10
1 #include "resize.hpp"
2 #include <stdexcept>
3 #include <iostream>
4 #include <zlib.h>
5 #include <cstring>
6 #include <map>
7 #include <string>
8 #include <sstream>
9 #include <cmath>
11 namespace
13 uint32_t decode32(const unsigned char* buf)
15 uint32_t v = 0;
16 v |= ((uint32_t)buf[0] << 24);
17 v |= ((uint32_t)buf[1] << 16);
18 v |= ((uint32_t)buf[2] << 8);
19 v |= ((uint32_t)buf[3]);
20 return v;
23 #define INBUF_SIZE 16384
24 #define OUTBUF_SIZE 16384
26 void decode_zlib(unsigned char* target, const unsigned char* src, uint32_t insize, uint32_t pixels)
28 unsigned char out[INBUF_SIZE];
29 unsigned char in[OUTBUF_SIZE];
30 uint32_t dptr = 0;
32 z_stream s;
33 memset(&s, 0, sizeof(s));
34 int r = inflateInit(&s);
35 if(r < 0) {
36 std::stringstream str;
37 str << "inflateInit: zlib error: " << s.msg;
38 throw std::runtime_error(str.str());
41 s.next_in = in;
42 s.avail_in = 0;
43 s.next_out = out;
44 s.avail_out = INBUF_SIZE;
46 while(1) {
47 uint32_t old_avail_out = s.avail_out;
49 if(s.avail_in == 0) {
50 if(insize > OUTBUF_SIZE) {
51 s.next_in = in;
52 s.avail_in = OUTBUF_SIZE;
53 memcpy(s.next_in, src, OUTBUF_SIZE);
54 src += OUTBUF_SIZE;
55 insize -= OUTBUF_SIZE;
56 } else {
57 s.next_in = in;
58 s.avail_in = insize;
59 memcpy(s.next_in, src, insize);
60 src += insize;
61 insize = 0;
65 r = inflate(&s, Z_NO_FLUSH);
66 if(r < 0) {
67 inflateEnd(&s);
68 std::stringstream str;
69 str << "inflate: zlib error: " << s.msg;
70 throw std::runtime_error(str.str());
72 dptr += (old_avail_out - s.avail_out);
73 if(s.avail_out == 0) {
74 memcpy(target, out, INBUF_SIZE);
75 target += INBUF_SIZE;
76 s.avail_out = INBUF_SIZE;
77 s.next_out = out;
79 if(dptr == 4 * pixels) {
80 memcpy(target, out, INBUF_SIZE - s.avail_out);
81 target += (INBUF_SIZE - s.avail_out);
82 s.avail_out = INBUF_SIZE;
83 s.next_out = out;
84 break;
86 if(r == Z_STREAM_END) {
87 inflateEnd(&s);
88 std::stringstream str;
89 str << "Uncompressed stream truncated";
90 throw std::runtime_error(str.str());
93 inflateEnd(&s);
98 const unsigned char* image_frame_rgbx::get_pixels() const
100 return imagedata;
103 unsigned char* image_frame_rgbx::get_pixels()
105 return imagedata;
108 uint32_t image_frame_rgbx::get_height() const
110 return height;
113 uint32_t image_frame_rgbx::get_width() const
115 return width;
118 image_frame_rgbx::~image_frame_rgbx()
120 delete[] imagedata;
123 image_frame_rgbx::image_frame_rgbx(uint32_t width, uint32_t height)
125 this->width = width;
126 this->height = height;
127 if(width && height) {
128 this->imagedata = new unsigned char[4 * width * height];
129 memset(this->imagedata, 0, 4 * width * height);
130 } else
131 this->imagedata = NULL;
134 image_frame_rgbx::image_frame_rgbx(const image_frame_rgbx& x)
136 this->width = x.width;
137 this->height = x.height;
138 if(width && height) {
139 this->imagedata = new unsigned char[4 * width * height];
140 memcpy(imagedata, x.imagedata, 4 * width * height);
141 } else
142 this->imagedata = NULL;
145 image_frame_rgbx& image_frame_rgbx::operator=(const image_frame_rgbx& x)
147 if(this == &x)
148 return *this;
149 unsigned char* old_imagedata = imagedata;
150 if(x.width && x.height)
151 this->imagedata = new unsigned char[4 * x.width * x.height];
152 else
153 this->imagedata = NULL;
154 this->width = x.width;
155 this->height = x.height;
156 if(x.width && x.height)
157 memcpy(imagedata, x.imagedata, 4 * width * height);
158 delete[] old_imagedata;
159 return *this;
162 image_frame_rgbx::image_frame_rgbx(struct packet& p)
164 if(p.rp_major != 0) {
165 std::stringstream str;
166 str << "frame_from_packet: Incorrect major type (" << p.rp_major << ", should be 0)";
167 throw std::runtime_error(str.str());
169 if(p.rp_minor != 0 && p.rp_minor != 1) {
170 std::stringstream str;
171 str << "frame_from_packet: Unknown minor type (" << p.rp_minor << ", should be 0 or 1)";
172 throw std::runtime_error(str.str());
174 if(p.rp_payload.size() < 4)
175 throw std::runtime_error("frame_from_packet: Malformed payload (image parameters missing)");
177 uint32_t ihdr = decode32(&p.rp_payload[0]);
178 width = ihdr / 65536;
179 height = ihdr % 65536;
180 imagedata = new unsigned char[4 * width * height];
182 if(p.rp_minor == 0)
183 memcpy(imagedata, &p.rp_payload[4], 4 * width * height);
184 else if(p.rp_minor == 1)
185 try {
186 decode_zlib(imagedata, &p.rp_payload[4], p.rp_payload.size() - 4, width * height);
187 } catch(...) {
188 delete[] imagedata;
189 imagedata = NULL;
190 throw;
194 size_t image_frame_rgbx::get_data_size() const
196 return 4 * width * height;
199 image_frame_rgbx& image_frame_rgbx::resize(uint32_t nwidth, uint32_t nheight, resizer& using_resizer)
201 if(width == nwidth && height == nheight)
202 return *this;
203 image_frame_rgbx* newf = new image_frame_rgbx(nwidth, nheight);
204 if(width == 0 && height == 0) {
205 //Fill with black.
206 memset(newf->get_pixels(), 0, newf->get_data_size());
207 return *newf;
209 using_resizer(newf->get_pixels(), nwidth, nheight, get_pixels(), width, height);
210 return *newf;
213 resizer::~resizer()
217 std::map<std::string, resizer_factory*>* resizer_factory::factories;
219 resizer_factory::~resizer_factory()
223 resizer_factory::resizer_factory(const std::string& type)
225 if(!factories)
226 factories = new std::map<std::string, resizer_factory*>();
227 (*factories)[type] = this;
230 resizer& resizer_factory::make_by_type(const std::string& type)
232 if(!factories || !factories->count(type))
233 throw std::runtime_error("Unknown output driver type");
234 return (*factories)[type]->make(type);
237 std::string get_resizer_list()
239 bool first = true;
240 if(!resizer_factory::factories)
241 return "";
242 std::string c;
243 std::map<std::string, resizer_factory*>& f = *resizer_factory::factories;
244 for(std::map<std::string, resizer_factory*>::iterator i = f.begin(); i != f.end(); ++i) {
245 if(first)
246 c = i->first;
247 else
248 c = c + " " + i->first;
249 first = false;
251 return c;
254 namespace
256 class simple_resizer_c : public resizer
258 public:
259 simple_resizer_c(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
260 const uint8_t* source, uint32_t swidth, uint32_t sheight))
262 resize_fn = _resize_fn;
265 void operator()(uint8_t* target, uint32_t twidth, uint32_t theight,
266 const uint8_t* source, uint32_t swidth, uint32_t sheight)
268 resize_fn(target, twidth, theight, source, swidth, sheight);
271 private:
272 void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
273 const uint8_t* source, uint32_t swidth, uint32_t sheight);
276 class simple_resizer_c2 : public resizer
278 public:
279 simple_resizer_c2(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
280 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo)
282 resize_fn = _resize_fn;
283 algo = _algo;
286 void operator()(uint8_t* target, uint32_t twidth, uint32_t theight,
287 const uint8_t* source, uint32_t swidth, uint32_t sheight)
289 resize_fn(target, twidth, theight, source, swidth, sheight, algo);
292 private:
293 void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
294 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo);
295 int algo;
299 simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
300 const uint8_t* source, uint32_t swidth, uint32_t sheight))
301 : resizer_factory(type)
303 resize_fn = _resize_fn;
304 resize_fn2 = NULL;
305 algo = 0;
308 simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight,
309 const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo)
310 : resizer_factory(type)
312 resize_fn = NULL;
313 resize_fn2 = _resize_fn;
314 algo = _algo;
317 resizer& simple_resizer::make(const std::string& type)
319 if(resize_fn)
320 return *new simple_resizer_c(resize_fn);
321 else
322 return *new simple_resizer_c2(resize_fn2, algo);