~ubuntu-branches/ubuntu/karmic/motion/karmic-proposed

« back to all changes in this revision

Viewing changes to netcam.c

  • Committer: Bazaar Package Importer
  • Author(s): Frederik Dannemare
  • Date: 2005-03-14 01:03:18 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050314010318-d5f9uk8m4lymiite
Tags: 3.1.19-1
* New upstream release (Closes: #297671).
* Add support for ffmpeg (add Build-Depends on libavcodec-dev and
  libavformat-dev).
* Update debian/README.Debian to mention the new support for ffmpeg.
* Remove debian/motion.menu (didn't make much sense really).
* Get rid of direct patching of upstream sources. Instead, apply
  Debian-specific modifications at build-time from patches in debian/patches
  with help from dpatch (add Build-Depends on dpatch).
* Remove Suggests on ucbmpeg (Closes: #279385).
* Add Recommends on ffmpeg.
* Include German po-debconf translation by Jens Nachtigall
  <nachtigall@web.de> (Closes: #283017).
* Patch configure to really remove rpath + add -lvorbis -lvorbisenc -ldts
  -la52 to LIBS. Thanks to Sam Hocevar (ffmpeg maintainer) for hints on
  how to properly build with ffmpeg support.
* Upload sponsored by Ari Pollak <ari@debian.org>.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      netcam.c
 
3
 *
 
4
 *      Copyright 2002 by Jeroen Vreeken (pe1rxq@amsat.org)
 
5
 *      Additional copyright 2005 Angel Carpintero and Christopher Price
 
6
 *      (only main contributors of this file listed).
 
7
 *      This software is distributed under the GNU Public License Version 2
 
8
 *      See also the file 'COPYING'.
 
9
 *
 
10
 */
 
11
 
 
12
#include "motion.h"
 
13
 
 
14
#ifdef __freebsd__
 
15
#include "video_freebsd.h"
 
16
#else
 
17
#include "video.h"
 
18
#endif /* __freebsd__ */
 
19
 
 
20
#include <netdb.h>
 
21
#include <netinet/in.h>
 
22
#include <sys/types.h>
 
23
#include <sys/socket.h>
 
24
#include <jpeglib.h>
 
25
#include <setjmp.h>
 
26
 
 
27
/* for rotation */
 
28
#include "rotate.h"
 
29
#include "netcam_wget.h"
 
30
 
 
31
#define REQUEST_AUTH "GET %s HTTP/1.0\r\nAuthorization: Basic %s\r\n\r\n"
 
32
#define REQUEST "GET %s HTTP/1.0\r\n\r\n"
 
33
#define TIMEOUT 30
 
34
 
 
35
typedef struct {
 
36
        struct jpeg_source_mgr pub;
 
37
        char *data;
 
38
        int length;
 
39
        JOCTET *buffer;
 
40
        boolean start_of_file;
 
41
} my_source_mgr;
 
42
 
 
43
typedef my_source_mgr *my_src_ptr;
 
44
 
 
45
struct my_error_mgr {
 
46
        struct jpeg_error_mgr pub;
 
47
        jmp_buf setjmp_buffer;
 
48
};
 
49
 
 
50
void my_init_source (j_decompress_ptr); 
 
51
boolean my_fill_input_buffer (j_decompress_ptr); 
 
52
void my_skip_input_data (j_decompress_ptr, long);
 
53
void my_term_source (j_decompress_ptr);
 
54
void jpeg_memory_src(j_decompress_ptr, char *, int);
 
55
void my_error_exit (j_common_ptr);
 
56
 
 
57
int netcam_check_JPEG(struct netcam_context *, int, int);
 
58
static void *netcam_loop(void *);
 
59
int netcam_read_header(struct netcam_context *, int);
 
60
int netcam_connect(struct netcam_context *);
 
61
int netcam_close(struct netcam_context *);
 
62
int netcam_read_image(struct netcam_context *);
 
63
int netcam_single_read(struct netcam_context *,int);
 
64
int netcam_read_image_no_content_length(struct netcam_context *,int);
 
65
int netcam_read_stream_no_content_length(struct netcam_context *,int);
 
66
int netcam_stream_read(struct netcam_context *,int);
 
67
int netcam_stream_reconnection(struct netcam_context *,int);
 
68
 
 
69
 
 
70
int netcam_start(struct context *);
 
71
unsigned char *netcam_next(struct context *, char *);
 
72
 
 
73
/*
 
74
        parses the url
 
75
*/
 
76
 
 
77
int netcam_parse_url (struct url_t *parse_url, char *text_url)
 
78
{
 
79
        char *dup;
 
80
        char *parse;
 
81
        char *p;
 
82
 
 
83
        dup = strdup(text_url);
 
84
        parse = dup;
 
85
        parse_url->service = NULL;
 
86
        parse_url->host = NULL;
 
87
        parse_url->port = 80;
 
88
        parse_url->path = NULL;
 
89
 
 
90
        if ((p = strstr (parse, ":/"))) {
 
91
                *p++ = '\0';
 
92
                if (p[0] == '/' && p[1] == '/') p += 2;
 
93
                parse_url->service = strdup (dup);
 
94
                parse = p;
 
95
        }
 
96
        
 
97
        p = strchr (parse, '/');
 
98
        
 
99
        if (!p || parse < p){
 
100
                char *p2;
 
101
                
 
102
                parse_url->host = strdup (parse);
 
103
                if (p) parse_url->host[p - parse] = '\0';
 
104
                if (*parse_url->host == '[') {
 
105
                        p2 = strchr (parse_url->host, ']');
 
106
                        if (p2) p2 = strchr (p2, ':');
 
107
                } else {
 
108
                        p2 = strchr (parse_url->host, ':');
 
109
                }
 
110
                if (p2) {
 
111
                        *p2++ = '\0';
 
112
                        parse_url->port = atoi (p2);
 
113
                }
 
114
        }
 
115
        parse = p;
 
116
        if (parse) parse_url->path = strdup (parse);
 
117
 
 
118
        free(parse_url->service);       
 
119
        free (dup);
 
120
        
 
121
        return 1;
 
122
}
 
123
 
 
124
 
 
125
/* 
 
126
        jpeglib init_source 
 
127
 
 
128
        overrided by own init_source routine.
 
129
        Initialize source --- called by jpeg_read_header
 
130
        before any data is actually read.
 
131
*/
 
132
 
 
133
void my_init_source (j_decompress_ptr cinfo) 
 
134
{
 
135
        my_src_ptr src = (my_src_ptr) cinfo->src;
 
136
        /* We reset the empty-input-file flag for each image,
 
137
        but we don't clear the input buffer.
 
138
        This is correct behavior for reading a series of images from one source.
 
139
        */
 
140
        src->start_of_file = TRUE;
 
141
}
 
142
 
 
143
/*
 
144
        jpeglib fill_input_buffer
 
145
 
 
146
        override by own fill_input_buffer routine.
 
147
        Fill the input buffer --- called whenever buffer is emptied
 
148
*/
 
149
 
 
150
boolean my_fill_input_buffer (j_decompress_ptr cinfo)
 
151
{
 
152
        my_src_ptr src = (my_src_ptr) cinfo->src;
 
153
        size_t nbytes;
 
154
        
 
155
        if (src->start_of_file) {
 
156
                nbytes=src->length;
 
157
                src->buffer=src->data;
 
158
        } else {
 
159
        // Insert a fake EOI marker - as per jpeglib recommendation
 
160
                src->buffer[0] = (JOCTET) 0xFF;
 
161
                src->buffer[1] = (JOCTET) JPEG_EOI; // 0xD9
 
162
                nbytes = 2;
 
163
        }
 
164
        
 
165
        src->pub.next_input_byte = src->buffer;
 
166
        src->pub.bytes_in_buffer = nbytes;
 
167
        src->start_of_file = FALSE;
 
168
        
 
169
        return TRUE;
 
170
}
 
171
 
 
172
/*
 
173
        jpeglib skip_input_data 
 
174
 
 
175
        override by own skip_input_data routine. 
 
176
        Skip data --- used to skip over a potentially large amount of
 
177
        uninteresting data
 
178
*/
 
179
 
 
180
void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
 
181
{
 
182
my_src_ptr src = (my_src_ptr) cinfo->src;
 
183
 
 
184
        if (num_bytes > 0) {
 
185
                while (num_bytes > (long) src->pub.bytes_in_buffer) {
 
186
                        num_bytes -= (long) src->pub.bytes_in_buffer;
 
187
                        (void) my_fill_input_buffer(cinfo);
 
188
                }
 
189
        src->pub.next_input_byte += (size_t) num_bytes;
 
190
        src->pub.bytes_in_buffer -= (size_t) num_bytes;
 
191
        }
 
192
}
 
193
 
 
194
/*
 
195
        jpeglib term_source 
 
196
 
 
197
        Terminate source --- called by jpeg_finish_decompress
 
198
        after all data has been read.  Often a no-op.
 
199
        NOT called by jpeg_abort or jpeg_destroy; surrounding
 
200
        application must deal with any cleanup that should happen even
 
201
        for error exit.
 
202
*/
 
203
void my_term_source (j_decompress_ptr cinfo) { }
 
204
 
 
205
/*
 
206
        jpeg_memory_src 
 
207
 
 
208
        Prepare for input from memory .
 
209
        The caller must have already allocated memory, and is responsible
 
210
        for freed it after finishing decompression.
 
211
*/
 
212
 
 
213
void jpeg_memory_src(j_decompress_ptr cinfo, char *data, int length)
 
214
{
 
215
        my_src_ptr src;
 
216
 
 
217
        if (cinfo->src == NULL) {
 
218
                cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
 
219
                        ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(my_source_mgr));
 
220
                src = (my_src_ptr) cinfo->src;
 
221
        }
 
222
 
 
223
        src = (my_src_ptr) cinfo->src;
 
224
        src->data = data;
 
225
        src->length = length;
 
226
        src->pub.init_source = my_init_source;
 
227
        src->pub.fill_input_buffer = my_fill_input_buffer;
 
228
        src->pub.skip_input_data = my_skip_input_data;
 
229
        src->pub.resync_to_restart = jpeg_resync_to_restart;
 
230
        src->pub.term_source = my_term_source;
 
231
        src->pub.bytes_in_buffer = 0;
 
232
        src->pub.next_input_byte = NULL;
 
233
}
 
234
 
 
235
 
 
236
/*
 
237
        jpeglib error_exit
 
238
 
 
239
        overrided by our own error_exit routine. 
 
240
        Triggered when a fatal error occurs.
 
241
*/
 
242
 
 
243
void my_error_exit (j_common_ptr cinfo)
 
244
{
 
245
        struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
 
246
        (*cinfo->err->output_message) (cinfo);
 
247
        /* Return control to the setjmp point */
 
248
        longjmp (myerr->setjmp_buffer, 1);
 
249
}
 
250
 
 
251
/*
 
252
        This function will do a sanity check over jpeg image , if an error is found
 
253
        read the header and return -1.
 
254
        Reference JFIF format http://www.w3.org/Graphics/JPEG/jfif3.pdf 
 
255
        
 
256
        If JPEG start or end are incorrect or connection error returns -1
 
257
        Else return 0
 
258
*/
 
259
int netcam_check_JPEG(struct netcam_context *netcam, int which_image, int connection){
 
260
        int error=0,ret;
 
261
 
 
262
        /* check jfif start */
 
263
        if (!memmem(netcam->image[which_image].buffer,3,"\xFF\xD8\xFF",3)) {
 
264
                fprintf(stderr,"Netcam thread %d : Error checking JPEG not start code \n",netcam->threadnr);
 
265
                error=1;
 
266
        }
 
267
        /* check jfif end */
 
268
        else if (!memmem(&netcam->image[which_image].buffer[netcam->image[which_image].size -2],
 
269
                2,"\xFF\xD9",2)) {
 
270
                fprintf(stderr,"Netcam thread %d : Error checking JPEG not end code \n",netcam->threadnr);
 
271
                error=1;
 
272
        }
 
273
                
 
274
        if (error) {
 
275
                if (connection) {
 
276
                        sleep(1);
 
277
                        if (netcam_connect(netcam) != 0) return -1;
 
278
                }
 
279
                do {
 
280
                        if (netcam->content_length) ret = netcam_read_header(netcam, 0);
 
281
                        else ret = netcam_read_header(netcam, 2);
 
282
                } while (ret == 0);
 
283
        }
 
284
        
 
285
        return error;
 
286
}
 
287
 
 
288
/*
 
289
        main thread
 
290
*/
 
291
 
 
292
static void *netcam_loop(void *arg)
 
293
{
 
294
        struct context *cnt = arg;
 
295
        syslog(LOG_DEBUG, "Netcam: thread %d: thread PID: %d",cnt->threadnr, getpid());
 
296
        fprintf(stderr, "Netcam: thread %d: thread PID: %d\n", cnt->threadnr, getpid());
 
297
        do {
 
298
                if (cnt->netcam->read(cnt->netcam,0) == -1) {
 
299
                        syslog(LOG_DEBUG, "Netcam: thread %d: broken connection, FATAL error", cnt->threadnr);
 
300
                        fprintf(stderr,"Netcam: thread %d: broken connection, FATAL error\n", cnt->threadnr);
 
301
                }
 
302
        } while (!cnt->finish);
 
303
 
 
304
 
 
305
        pthread_mutex_lock(&cnt->netcam->image[0].mutex);
 
306
        pthread_mutex_lock(&cnt->netcam->image[1].mutex);
 
307
 
 
308
        /* Clean up Memory */
 
309
        if (cnt->netcam->image[0].buffer) free(cnt->netcam->image[0].buffer);
 
310
        if (cnt->netcam->image[1].buffer) free(cnt->netcam->image[1].buffer);
 
311
        if ((cnt->conf.netcam_userpass) && (cnt->netcam->userpass)) free(cnt->netcam->userpass);
 
312
        if (cnt->netcam->boundary_string) free(cnt->netcam->boundary_string);
 
313
        if (cnt->netcam->url.host) free(cnt->netcam->url.host);
 
314
        if (cnt->netcam->url.path) free(cnt->netcam->url.path);
 
315
        if (cnt->netcam->response) free(cnt->netcam->response);
 
316
 
 
317
        pthread_mutex_unlock(&cnt->netcam->image[0].mutex);
 
318
        pthread_mutex_unlock(&cnt->netcam->image[1].mutex);
 
319
 
 
320
        fprintf(stderr, "Netcam: thread %d: Exiting\n",cnt->netcam->threadnr);
 
321
        if (cnt->netcam) free(cnt->netcam);
 
322
 
 
323
        
 
324
        return 0;
 
325
}
 
326
 
 
327
/*
 
328
        if Content-Length is not supplied i.ex Axis 2100 , this function have to get 
 
329
        the boundary string for mjpeg.
 
330
        i.ex "Content-Type: multipart/x-mixed-replace; boundary=--myboundary".
 
331
 
 
332
        On Error Return  -1 Header Uknown
 
333
                         -2 Header Error
 
334
        On Success       > 0
 
335
*/
 
336
 
 
337
int netcam_read_header(struct netcam_context *netcam, int initial)
 
338
{
 
339
        char *header,*conttype;
 
340
        int status,hcount=0;
 
341
        
 
342
        while (1) {
 
343
                status = header_get (netcam->response, &header, HG_NONE);
 
344
        
 
345
                if (status == HG_ERROR) {
 
346
#if 0
 
347
                        syslog(LOG_ERR, "Netcam: thread %d: error reading header: [%s]", netcam->threadnr, header);
 
348
                        fprintf (stderr,"Netcam: thread %d: error reading header\nheader:\n [%s]\n",netcam->threadnr, header);
 
349
#endif                  
 
350
                        free(header);
 
351
                        return -2;
 
352
                }
 
353
#if 0
 
354
                else if (status == HG_EOF) {
 
355
                        syslog(LOG_ERR, "Netcam: thread %d: error reading header: [%s]", netcam->threadnr, header);
 
356
                        fprintf (stderr,"Netcam: thread %d: error reading header\nheader:\n [%s]\n", netcam->threadnr, header);
 
357
                }
 
358
#endif          
 
359
                
 
360
                if (hcount == 0 && initial == 1) {
 
361
                        /* process http ok ... or any other error header response */
 
362
                        fprintf(stderr,"[%s]\n",header);
 
363
                }
 
364
                
 
365
                if ( (header_process (header, "Content-Length", header_extract_number,
 
366
                        &netcam->image[netcam->which_image].size) ) ) {
 
367
                        netcam->content_length=1;
 
368
                } else if ((initial == 1) && (header_process (header, "Content-Type",
 
369
                        http_process_type, &conttype) ))
 
370
                {
 
371
                        if (strcmp("multipart/x-mixed-replace", conttype) == 0) {
 
372
                                char *bound;
 
373
                                fprintf(stderr, "Netcam: thread %d, mjpeg stream\n", netcam->threadnr);
 
374
                                /* Set the bondary string following Content-Type */
 
375
                                if ( (!netcam->boundary_string) && (bound = strstr(header,"boundary=")) ) {
 
376
                                        bound = bound + 9;
 
377
                                        netcam->boundary_string = strdup(bound);
 
378
                                        fprintf(stderr, "Netcam: thread %d: netcam->boundary_string [%s]\n", netcam->threadnr, netcam->boundary_string);
 
379
                                }
 
380
                                netcam->read = (void *) netcam_stream_read;
 
381
                        } else if (strcmp("image/jpeg", conttype) == 0) {
 
382
                                fprintf(stderr, "Netcam: thread %d: jpeg file\n", netcam->threadnr);
 
383
                                netcam->read = (void *) netcam_single_read;
 
384
                        } else {
 
385
                                syslog(LOG_ERR, "Netcam: thread %d: unknown Content-Type", netcam->threadnr);
 
386
                                fprintf (stderr,"Netcam: thread %d: unknown Content-Type\n", netcam->threadnr);
 
387
                                free(header);
 
388
                                return -1;
 
389
                        }
 
390
                        if (conttype) free(conttype);
 
391
                } else if (!*header) {
 
392
                        free (header);
 
393
                        break;
 
394
                }
 
395
                
 
396
                hcount++;
 
397
                free (header);
 
398
        }
 
399
        
 
400
        return hcount;
 
401
}
 
402
 
 
403
/*
 
404
        Establish netcam connection , it has a 5 seconds timeout
 
405
        On Success return 0
 
406
        On Error   return -1
 
407
*/
 
408
 
 
409
int netcam_connect(struct netcam_context *netcam)
 
410
{
 
411
        int sock;
 
412
        struct sockaddr_in server;
 
413
        struct hostent *host_info;
 
414
        struct timeval tv;      
 
415
        char *request;
 
416
        
 
417
        sock = socket(PF_INET, SOCK_STREAM, 0);
 
418
        if (sock < 0) {
 
419
                syslog(LOG_ERR, "Netcam: thread %d: failed to create socket : %s", netcam->threadnr, strerror(errno));
 
420
                fprintf(stderr,"Netcam: thread %d: failed to create socket : %s\n", netcam->threadnr, strerror(errno)); 
 
421
                return -1;
 
422
        }
 
423
        
 
424
        memset(&server, 0, sizeof(server));
 
425
        host_info = gethostbyname(netcam->url.host);
 
426
        if (host_info == NULL) {
 
427
                syslog(LOG_ERR, "Netcam: thread %d: unknown server: %s", netcam->threadnr, netcam->url.host);
 
428
                fprintf(stderr,"Netcam: thread %d: unknown server: %s\n", netcam->threadnr, netcam->url.host);
 
429
                close(sock);
 
430
                return -1;
 
431
        }
 
432
        
 
433
        memcpy((char *) &server.sin_addr, host_info->h_addr, host_info->h_length);
 
434
        
 
435
        server.sin_family = AF_INET;
 
436
        server.sin_port = htons(netcam->url.port);
 
437
        
 
438
        /* 5 seconds timeout */
 
439
        tv.tv_sec = 5;
 
440
        tv.tv_usec = 0;
 
441
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
 
442
        
 
443
        if (connect (sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
 
444
                syslog(LOG_ERR, "Netcam: thread %d: can't connect to server", netcam->threadnr);
 
445
                fprintf(stderr,"Netcam: thread %d: can't connect to server\n", netcam->threadnr);
 
446
                return -1;
 
447
        }
 
448
        
 
449
        if (netcam->userpass != NULL) {
 
450
                request = (char *) mymalloc(strlen(REQUEST_AUTH) +
 
451
                        strlen(netcam->url.path) + strlen(netcam->userpass) - 4 + 1);
 
452
                sprintf(request, REQUEST_AUTH, netcam->url.path, netcam->userpass);
 
453
        } else {
 
454
                request = (char *) mymalloc(strlen(REQUEST) +
 
455
                          strlen(netcam->url.path) + 1);
 
456
                sprintf(request, REQUEST, netcam->url.path);
 
457
        }
 
458
        
 
459
        rbuf_initialize(netcam->response, sock);
 
460
        
 
461
        send(RBUF_FD(netcam->response), request, strlen(request), 0);
 
462
        
 
463
        free(request);
 
464
        
 
465
        return 0;
 
466
}
 
467
 
 
468
/*
 
469
        Close netcam connection , only for single image.
 
470
*/
 
471
int netcam_close(struct netcam_context *netcam)
 
472
{
 
473
        if (netcam->response->fd == -1) return 0;
 
474
        close(RBUF_FD(netcam->response));
 
475
        netcam->response->fd = -1;
 
476
        return 0;
 
477
}
 
478
 
 
479
 
 
480
/*
 
481
        Try to reconnect to the stream and get a frame
 
482
 
 
483
        On Success return  1
 
484
        On Error   return -1
 
485
*/
 
486
int netcam_stream_reconnection(struct netcam_context *netcam,int which_image)
 
487
{
 
488
        int ret=-1,num_errors=-1;
 
489
        
 
490
        netcam_close(netcam);
 
491
 
 
492
        if (netcam->boundary_string) {
 
493
                free(netcam->boundary_string);
 
494
                netcam->boundary_string=NULL;
 
495
        }       
 
496
 
 
497
        netcam->content_length=0;       
 
498
 
 
499
        while ((netcam_connect(netcam) == -1) && (num_errors < 10)) {
 
500
                num_errors++;
 
501
                syslog(LOG_ERR,"Netcam: thread %d: error connecting , retrying [%d]", netcam->threadnr, num_errors);
 
502
                fprintf(stderr,"Netcam: thread %d: error connecting , retrying [%d]\n", netcam->threadnr, num_errors);
 
503
                sleep(5);
 
504
        }
 
505
 
 
506
        if (num_errors < 10) {
 
507
                syslog(LOG_ERR,"Netcam: thread %d: re-connection done", netcam->threadnr);
 
508
                fprintf(stderr,"Netcam: thread %d: re-connection done\n", netcam->threadnr);
 
509
        
 
510
                do {
 
511
                        ret = netcam_read_header(netcam, 1);
 
512
                } while (ret == 0);
 
513
        
 
514
                do {
 
515
                        if (netcam->content_length)
 
516
                                ret = netcam_read_header(netcam, 0);
 
517
                        else
 
518
                                ret = netcam_read_header(netcam, 2);
 
519
                } while (ret == 0);
 
520
                
 
521
                if (netcam->content_length)
 
522
                        ret = netcam_read_image(netcam);
 
523
                else
 
524
                        ret = netcam_read_stream_no_content_length(netcam,which_image);
 
525
        
 
526
                if (ret) {
 
527
                        syslog(LOG_ERR,"Netcam: thread %d: re-connection got frame", netcam->threadnr);
 
528
                        fprintf(stderr,"Netcam: thread %d: re-connection got frame\n", netcam->threadnr);
 
529
                }
 
530
                else if (!netcam_check_JPEG(netcam,which_image,0)) {
 
531
                        syslog(LOG_ERR,"Netcam: thread %d: re-connection did not get frame", netcam->threadnr);
 
532
                        fprintf(stderr,"Netcam: thread %d: re-connection did not get frame\n", netcam->threadnr);
 
533
                        ret = -1;
 
534
                }
 
535
        }
 
536
        
 
537
        return ret;
 
538
}
 
539
 
 
540
/*
 
541
        AXIS 2100 
 
542
        --myboundary^M
 
543
        Content-Type: image/jpeg^M
 
544
        <image>^M
 
545
        --myboundary^M
 
546
        Content-Type: image/jpeg^M
 
547
        <image>^M
 
548
        [ .... ]
 
549
        
 
550
        netcam stream read function for Non Content-Length support devices.
 
551
        On Success returns 1
 
552
        On Error returns -1
 
553
*/
 
554
int netcam_read_stream_no_content_length(struct netcam_context *netcam,int which_image)
 
555
{
 
556
        int cur_size=0,readb=0;
 
557
        size_t boundary_string_length;
 
558
        char *pointer_boundary=NULL,*pointer_init=NULL;
 
559
        
 
560
 
 
561
        /* FIXME !? */
 
562
        cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer,100000);
 
563
        boundary_string_length = strlen(netcam->boundary_string); 
 
564
        
 
565
        /*
 
566
                Get the image until find jpeg header ( JFIF v3 )
 
567
        */
 
568
 
 
569
        // Get the init of the image
 
570
        if (cur_size != 0){
 
571
                pointer_init = memmem(netcam->image[which_image].buffer,cur_size,"\xFF\xD8\xFF",3);
 
572
                if (pointer_init){
 
573
                        int init_read=0,end_read=0;
 
574
                        init_read = pointer_init - netcam->image[which_image].buffer;
 
575
                        if (init_read != 0){
 
576
                                end_read = cur_size - init_read;
 
577
                                memmove(netcam->image[which_image].buffer,&netcam->image[which_image].buffer[init_read],end_read);
 
578
                                cur_size = end_read;
 
579
                        }       
 
580
                }
 
581
        }
 
582
        
 
583
        while (!pointer_init){
 
584
                readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
 
585
                cur_size+=readb;
 
586
                pointer_init = memmem(netcam->image[which_image].buffer,cur_size,"\xFF\xD8\xFF",3);
 
587
                if (pointer_init){
 
588
                        int init_read=0,end_read=0;
 
589
                        init_read = pointer_init - netcam->image[which_image].buffer;
 
590
                        end_read = cur_size - init_read;
 
591
                        memmove(netcam->image[which_image].buffer,&netcam->image[which_image].buffer[init_read],end_read);
 
592
                        cur_size = end_read;
 
593
                }
 
594
        }
 
595
        
 
596
        
 
597
 
 
598
        /*
 
599
         * Get the image until find the next STREAM HEADER
 
600
         */
 
601
        
 
602
        do {
 
603
                readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
 
604
                if (readb < 0) {
 
605
                        syslog(LOG_ERR,"Netcam: thread %d: error reading stream : %s", netcam->threadnr, strerror(errno));
 
606
                        fprintf(stderr,"Netcam: thread %d: error reading stream : %s\n", netcam->threadnr, strerror(errno));
 
607
                        return -1;
 
608
                }
 
609
                cur_size += readb;
 
610
                if ( (pointer_boundary = memmem(netcam->image[which_image].buffer,
 
611
                        cur_size,netcam->boundary_string, boundary_string_length)) ) {
 
612
                        cur_size = pointer_boundary - netcam->image[which_image].buffer;
 
613
                }
 
614
        } while (!pointer_boundary);
 
615
 
 
616
        if ( (pointer_boundary = memmem(netcam->image[which_image].buffer,cur_size,"\xFF\xD9",2)) == NULL){
 
617
                fprintf(stderr,"Netcam: thread %d: Bad Jpeg end\n",netcam->threadnr);
 
618
                netcam->image[which_image].buffer_size = cur_size -4;
 
619
                netcam->image[which_image].size = cur_size -4;
 
620
        }else{
 
621
                netcam->image[which_image].buffer_size = (pointer_boundary - netcam->image[which_image].buffer)+2;
 
622
                netcam->image[which_image].size = netcam->image[which_image].buffer_size; 
 
623
        }                
 
624
 
 
625
 
 
626
        return 1;
 
627
}
 
628
 
 
629
 
 
630
/*
 
631
        netcam image read function for Non Content-Length support devices
 
632
        On Success returns 1
 
633
        On Error   returns -1
 
634
*/
 
635
int netcam_read_image_no_content_length(struct netcam_context *netcam,int which_image)
 
636
{
 
637
        int cur_size,readb;
 
638
        
 
639
        
 
640
        /* FIXME !? */
 
641
        cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer, 100000);
 
642
        
 
643
        do {
 
644
                readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
 
645
                cur_size += readb;
 
646
        } while ((readb > 0) && (cur_size < 100000));
 
647
        
 
648
        if ((readb < 0) || (cur_size > 100000)){
 
649
                syslog(LOG_ERR, "Netcam: thread %d: error reading image : %s", netcam->threadnr, strerror(errno));
 
650
                fprintf(stderr,"Netcam: thread %d: error reading image : %s\n", netcam->threadnr, strerror(errno));
 
651
                return -1;
 
652
        }
 
653
        netcam->image[which_image].buffer_size = cur_size;
 
654
        netcam->image[which_image].size = cur_size;
 
655
        
 
656
        return 1;
 
657
}
 
658
 
 
659
 
 
660
/*
 
661
        netcam stream/image read function for Content-Length support devices
 
662
        On Success returns 1
 
663
        On Error   returns -1
 
664
*/
 
665
int netcam_read_image(struct netcam_context *netcam)
 
666
{
 
667
        int which_image,cur_size,cur_left;
 
668
        
 
669
        which_image = netcam->which_image;
 
670
        if (netcam->image[which_image].size > netcam->image[which_image].buffer_size) {
 
671
                netcam->image[which_image].buffer_size = netcam->image[which_image].size;
 
672
                netcam->image[which_image].buffer =
 
673
                     myrealloc(netcam->image[which_image].buffer,
 
674
                               netcam->image[which_image].buffer_size,"netcam_stream_read");
 
675
        }
 
676
        
 
677
        cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer,
 
678
                              netcam->image[which_image].buffer_size);
 
679
        
 
680
        while (netcam->image[which_image].size > cur_size) {
 
681
                cur_left = recv(netcam->response->fd,&netcam->image[which_image].buffer[cur_size],
 
682
                                netcam->image[which_image].size - cur_size, 0);
 
683
                if (cur_left < 0) {
 
684
                        syslog(LOG_ERR, "Netcam: thread %d: error reading image, not complete", netcam->threadnr);
 
685
                        fprintf (stderr,"Netcam: thread %d: error reading image, not complete\n", netcam->threadnr);
 
686
                        netcam->image[which_image].size = 0;
 
687
                        return -1;
 
688
                }
 
689
                cur_size += cur_left;
 
690
        }
 
691
        
 
692
        return 1;
 
693
}       
 
694
 
 
695
/*
 
696
        netcam image read function
 
697
        On Success returns 1
 
698
        On Error   returns -1
 
699
*/
 
700
int netcam_single_read(struct netcam_context *netcam,int initial)
 
701
{
 
702
        int which_image,ret,num_errors=-1;
 
703
 
 
704
        if (initial) netcam_close(netcam); 
 
705
        
 
706
        while (netcam_connect(netcam) == -1) {
 
707
                num_errors++;
 
708
                syslog(LOG_ERR,"Netcam: thread %d: error connecting, retrying [%d]", netcam->threadnr, num_errors);
 
709
                fprintf(stderr,"Netcam: thread %d: error connecting, retrying [%d]\n", netcam->threadnr, num_errors);
 
710
                if (num_errors == 10) {
 
711
                        syslog(LOG_ERR,"Netcam: thread %d: Error Connection LOST , waiting 1 minute", netcam->threadnr);
 
712
                        fprintf(stderr,"Netcam: thread %d: Error Connection LOST waiting 1 minute\n", netcam->threadnr);
 
713
                        sleep(60);
 
714
                }
 
715
                sleep(5);
 
716
        }
 
717
        
 
718
 
 
719
        pthread_mutex_lock(&netcam->mutex);
 
720
        which_image = netcam->which_image = !netcam->which_image;
 
721
        pthread_mutex_unlock(&netcam->mutex);
 
722
        
 
723
        do {
 
724
                if (initial){
 
725
                        netcam->content_length=0;
 
726
                        ret = netcam_read_header(netcam, 2);
 
727
                        if (netcam->content_length){
 
728
                                fprintf(stderr,"Netcam single: thread %d: Content-length supported \n", netcam->threadnr);
 
729
                        }else{
 
730
                                fprintf(stderr,"Netcam single: thread %d : Content-length NO supported \n", netcam->threadnr);
 
731
                        }
 
732
                }
 
733
                else {
 
734
                        ret = netcam_read_header(netcam, 0);
 
735
                }
 
736
        } while (ret == 0);
 
737
 
 
738
        pthread_mutex_lock(&netcam->image[which_image].mutex);
 
739
        
 
740
        if (netcam->content_length)
 
741
                ret = netcam_read_image(netcam);
 
742
        else
 
743
                ret = netcam_read_image_no_content_length(netcam,which_image);
 
744
        netcam_close(netcam);
 
745
        
 
746
        if ( (ret != -1) && (netcam_check_JPEG(netcam,which_image,1) != -1) ) {
 
747
                netcam->image[which_image].filled = 1;
 
748
                pthread_cond_signal(&netcam->image[which_image].buffer_filled);
 
749
                netcam_close(netcam);
 
750
        } else {
 
751
                netcam->error_frames++;
 
752
                syslog(LOG_ERR,"Netcam: thread %d: error frame [%d]", netcam->threadnr, netcam->error_frames);
 
753
                fprintf(stderr,"Netcam: thread %d: error frame [%d]\n", netcam->threadnr, netcam->error_frames);
 
754
                if (netcam->error_frames == 100){ 
 
755
                        netcam->error_frames=0;
 
756
                        syslog(LOG_INFO,"Netcam: thread %d: error frame reset to 0", netcam->threadnr);
 
757
                        fprintf(stderr,"Netcam: thread %d: error frame reset to 0\n", netcam->threadnr);
 
758
                }
 
759
                ret=1;
 
760
                netcam_close(netcam);
 
761
        }
 
762
        
 
763
        pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
764
        
 
765
        return ret;
 
766
}
 
767
 
 
768
/*
 
769
        netcam stream read function
 
770
        On Success returns 1 <- !?
 
771
        On Error returns -1
 
772
*/
 
773
int netcam_stream_read(struct netcam_context *netcam,int initial)
 
774
{
 
775
        int which_image,ret,num_errors=-1;
 
776
        
 
777
        pthread_mutex_lock(&netcam->mutex);
 
778
        which_image = netcam->which_image = !netcam->which_image;
 
779
        pthread_mutex_unlock(&netcam->mutex);
 
780
 
 
781
        do {
 
782
                if (initial) {
 
783
                        netcam->content_length=0;
 
784
                        ret = netcam_read_header(netcam, 0);
 
785
                        if (netcam->content_length){
 
786
                                fprintf(stderr,"Netcam stream : thread %d: Content-length supported \n", netcam->threadnr);
 
787
                        }else{
 
788
                                fprintf(stderr,"Netcam stream : thread %d: Content-length NO supported \n", netcam->threadnr);
 
789
                        }
 
790
                        // Check if boundary_string exits
 
791
                        if (!netcam->boundary_string){
 
792
                                netcam->image[which_image].size=0;
 
793
                                netcam_close(netcam);
 
794
                                syslog(LOG_ERR,"Netcam: thread %d: BOUNDARY STRING not found", netcam->threadnr);
 
795
                                fprintf(stderr,"Netcam: thread %d: BOUNDARY STRING not found\n", netcam->threadnr);
 
796
                                return -1;
 
797
                        }
 
798
                }
 
799
                else {
 
800
                        if (netcam->content_length)
 
801
                                ret = netcam_read_header(netcam, 0);
 
802
                        else
 
803
                                ret = netcam_read_header(netcam, 2);
 
804
                }
 
805
        } while (ret == 0);
 
806
        
 
807
        pthread_mutex_lock(&netcam->image[which_image].mutex);
 
808
        
 
809
        do {
 
810
                if (netcam->content_length)
 
811
                        ret = netcam_read_image(netcam);
 
812
                else
 
813
                        ret = netcam_read_stream_no_content_length(netcam,which_image);
 
814
                num_errors++;
 
815
                if (ret == -1)
 
816
                        break;
 
817
        } while ( ((netcam_check_JPEG(netcam,which_image,0)) == -1) && (num_errors < 10));
 
818
        
 
819
        if ((ret == -1) || (num_errors == 10)){
 
820
                if ( num_errors == 10) {
 
821
                        syslog(LOG_ERR,"Netcam: thread %d: too many JPEG errors", netcam->threadnr);
 
822
                        fprintf(stderr,"Netcam: thread %d: too many JPEG errors\n", netcam->threadnr);
 
823
                        num_errors = -1;
 
824
                }
 
825
                while (netcam_stream_reconnection(netcam,which_image) == -1) {
 
826
                        syslog(LOG_ERR,"Netcam: thread %d: error reconnecting, waiting a minute", netcam->threadnr);
 
827
                        fprintf(stderr,"Netcam: thread %d: errors reconnecting, waiting a minute\n", netcam->threadnr);
 
828
                        sleep(60); 
 
829
                }
 
830
                ret=1;
 
831
        } 
 
832
        
 
833
        netcam->image[which_image].filled=1;    
 
834
        pthread_cond_signal(&netcam->image[which_image].buffer_filled);
 
835
        pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
836
        
 
837
        return ret;
 
838
}
 
839
 
 
840
 
 
841
/*
 
842
        netcam init called function , it establishes connection to network device, gets
 
843
        the image or the stream and creates the read thread.
 
844
*/
 
845
 
 
846
int netcam_start(struct context *cnt)
 
847
{
 
848
        struct jpeg_decompress_struct cinfo;
 
849
        struct jpeg_error_mgr jerr;
 
850
        pthread_attr_t thread_attr;
 
851
        pthread_t thread_id;
 
852
        struct netcam_context *netcam;
 
853
        
 
854
        
 
855
        syslog(LOG_INFO, "Netcam: thread %d: starting...", cnt->threadnr);
 
856
        fprintf(stderr,"Netcam: thread %d: starting...\n", cnt->threadnr);
 
857
        
 
858
        cnt->netcam = (struct netcam_context *) mymalloc(sizeof(struct netcam_context));
 
859
        netcam = cnt->netcam;
 
860
        netcam->threadnr = cnt->threadnr;
 
861
        netcam->boundary_string = NULL;
 
862
        
 
863
        pthread_mutex_init(&netcam->mutex, NULL);
 
864
        pthread_mutex_init(&netcam->image[0].mutex, NULL);
 
865
        pthread_mutex_init(&netcam->image[1].mutex, NULL);
 
866
        // Conditional pthread variables ( replaces semaphores in pthread )
 
867
        pthread_cond_init(&netcam->image[0].buffer_filled,NULL);
 
868
        pthread_cond_init(&netcam->image[1].buffer_filled,NULL);
 
869
        netcam->image[0].filled=0;
 
870
        netcam->image[1].filled=0;
 
871
        netcam->error_frames=0;
 
872
        netcam->userpass = NULL;
 
873
        
 
874
        netcam_parse_url (&netcam->url, cnt->conf.netcam_url);
 
875
        
 
876
        if (cnt->conf.netcam_userpass) {
 
877
                netcam->userpass = (char *) mymalloc(BASE64_LENGTH(strlen(cnt->conf.netcam_userpass))+1);
 
878
                {
 
879
                        char *userpass=mymalloc(strlen(cnt->conf.netcam_userpass)+4);
 
880
                        /* base64_encode can read 3 bytes after the end of the string,
 
881
                        initialize it */
 
882
                        memset(userpass,0,strlen(cnt->conf.netcam_userpass)+4);
 
883
                        strcpy(userpass,cnt->conf.netcam_userpass);
 
884
                        base64_encode(userpass, netcam->userpass, strlen(cnt->conf.netcam_userpass));
 
885
                        free(userpass);
 
886
                }
 
887
        }       
 
888
        
 
889
        netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf));
 
890
        
 
891
        /* 
 
892
                image buffer should be set for Non Content-Length support devices.
 
893
                FIXME : Maybe it should not be hardcoded here !?
 
894
        */
 
895
        
 
896
        netcam->image[0].buffer_size = 100000;
 
897
        netcam->image[0].size = 0;
 
898
        netcam->image[0].buffer = (char *) mymalloc(netcam->image[0].buffer_size);
 
899
        netcam->image[1].buffer_size = 100000;
 
900
        netcam->image[1].size = 0;
 
901
        netcam->image[1].buffer = (char *) mymalloc(netcam->image[1].buffer_size);
 
902
        netcam->which_image = 0;
 
903
        
 
904
        /* Initial Connection to Netcam */
 
905
        if (netcam_connect(netcam) != 0){
 
906
                if ((cnt->conf.netcam_userpass) && (netcam->userpass)) free(netcam->userpass);
 
907
                if (netcam->response) free(netcam->response);
 
908
                free(netcam->image[0].buffer);
 
909
                free(netcam->image[1].buffer);
 
910
                if (netcam->url.path) free(netcam->url.path);
 
911
                if (netcam->url.host) free(netcam->url.host);
 
912
                free(netcam);
 
913
                return -1;
 
914
        }
 
915
        
 
916
        /* Initial header read , as specified passing as parameter 1 */ 
 
917
        if ( netcam_read_header(netcam, 1) < 0){
 
918
                if ((cnt->conf.netcam_userpass) && (netcam->userpass)) free(netcam->userpass);
 
919
                if (netcam->response) free(netcam->response);
 
920
                free(netcam->image[0].buffer);
 
921
                free(netcam->image[1].buffer);
 
922
                if (netcam->boundary_string) free(netcam->boundary_string);
 
923
                if (netcam->url.path) free(netcam->url.path);
 
924
                if (netcam->url.host) free(netcam->url.host);
 
925
                free(netcam);   
 
926
                return -1;
 
927
        }
 
928
        
 
929
        /* Call to fetch image or stream function */
 
930
        netcam->read(netcam,1);
 
931
 
 
932
        if (netcam->image[netcam->which_image].size > 0) {
 
933
                netcam->image[netcam->which_image].filled=0;
 
934
                cinfo.err = jpeg_std_error(&jerr);
 
935
                jpeg_create_decompress(&cinfo);
 
936
                jpeg_memory_src(&cinfo, netcam->image[netcam->which_image].buffer,
 
937
                                netcam->image[netcam->which_image].size);
 
938
                jpeg_read_header(&cinfo, TRUE);
 
939
                
 
940
                cnt->imgs.width=cinfo.image_width;
 
941
                cnt->imgs.height=cinfo.image_height;
 
942
                cnt->imgs.size=cnt->imgs.width*cnt->imgs.height*3/2;
 
943
                cnt->imgs.motionsize=cnt->imgs.width*cnt->imgs.height;
 
944
                cnt->imgs.type=VIDEO_PALETTE_YUV420P;
 
945
                
 
946
                /* Create the netcam loop thread */
 
947
                pthread_attr_init(&thread_attr);
 
948
                pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
 
949
                pthread_create(&thread_id, &thread_attr, &netcam_loop, cnt);
 
950
        } else {
 
951
                fprintf(stderr,"Netcam netcam_start(): thread %d: Image size %d\n",
 
952
                        netcam->threadnr, (int)netcam->image[netcam->which_image].size);
 
953
                if (netcam->image[0].buffer) free(netcam->image[0].buffer);
 
954
                if (netcam->image[1].buffer) free(netcam->image[1].buffer);
 
955
                if ((cnt->conf.netcam_userpass) && (netcam->userpass)) free(netcam->userpass);
 
956
                if (netcam->boundary_string) free(netcam->boundary_string);
 
957
                if (netcam->url.path) free(netcam->url.path);
 
958
                if (netcam->url.host) free(netcam->url.host);
 
959
                if (netcam->response) free(netcam->response);
 
960
                if (netcam) free(netcam);
 
961
                return -1;
 
962
        }
 
963
        return 0;
 
964
}
 
965
 
 
966
 
 
967
/*
 
968
        netcam process image function , is called by motion thread to get an image
 
969
        from netcam read thread.
 
970
*/
 
971
 
 
972
unsigned char *netcam_next(struct context *cnt, char *image)
 
973
{
 
974
        struct jpeg_decompress_struct cinfo;
 
975
        struct my_error_mgr jerr;
 
976
        unsigned char *pic, *upic, *vpic;
 
977
        JSAMPARRAY line;
 
978
        int i, line_size, y,which_image,ret;
 
979
        JSAMPROW row[1];
 
980
        int width, height;                 /* for rotation */
 
981
        struct netcam_context *netcam;
 
982
        struct timespec now;
 
983
 
 
984
        pic = NULL;
 
985
        netcam = cnt->netcam;
 
986
        
 
987
        pthread_mutex_lock(&netcam->mutex);
 
988
        which_image = !netcam->which_image;
 
989
        if (!netcam->image[which_image].filled)
 
990
                which_image = netcam->which_image;
 
991
        pthread_mutex_unlock(&netcam->mutex);
 
992
        
 
993
        pthread_mutex_lock(&netcam->image[which_image].mutex);
 
994
 
 
995
        while ((!netcam->image[which_image].filled) && (!cnt->finish)) {
 
996
                memset(&now, 0, sizeof now);
 
997
                now.tv_sec=time(0)+5;
 
998
                now.tv_nsec=0;
 
999
                ret = pthread_cond_timedwait(&netcam->image[which_image].buffer_filled,&netcam->image[which_image].mutex,
 
1000
                                        &now);
 
1001
                 if (ret == ETIMEDOUT) { 
 
1002
                        if ((!netcam->image[which_image].filled) && (!cnt->finish)) { 
 
1003
                        /* Code for time-out condition */
 
1004
                                fprintf(stderr,"Thread %d Condiction timeout\n",netcam->threadnr); 
 
1005
                        } else { 
 
1006
                        /* success condition */ 
 
1007
                        break; 
 
1008
                        }
 
1009
                } 
 
1010
        }
 
1011
 
 
1012
        if (cnt->finish){
 
1013
                pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
1014
                return NULL;    
 
1015
        }
 
1016
 
 
1017
        netcam->image[which_image].filled = 0;
 
1018
        if (netcam->image[which_image].size > 0){
 
1019
                cinfo.err = jpeg_std_error(&jerr.pub);
 
1020
                jerr.pub.error_exit = my_error_exit;
 
1021
                
 
1022
                if (setjmp(jerr.setjmp_buffer)) {
 
1023
                        jpeg_destroy_decompress(&cinfo);
 
1024
                        pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
1025
                        return pic;
 
1026
                }
 
1027
                
 
1028
                jpeg_create_decompress(&cinfo);
 
1029
                jpeg_memory_src(&cinfo, netcam->image[which_image].buffer,netcam->image[which_image].size);
 
1030
                jpeg_read_header(&cinfo, TRUE);
 
1031
                
 
1032
                cinfo.out_color_space = JCS_YCbCr;
 
1033
                
 
1034
                /* NOTE: Since this is a capture, we need to use the capture dimensions. */
 
1035
                /* POSSIBLE BUG: What if the netcam changes resolution? */
 
1036
                
 
1037
                width = cnt->rotate_data.cap_width;
 
1038
                height = cnt->rotate_data.cap_height;
 
1039
                
 
1040
                jpeg_start_decompress(&cinfo);
 
1041
                line_size = width * 3;
 
1042
                
 
1043
                line = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo,
 
1044
                        JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
 
1045
                pic = image;
 
1046
                upic = pic + width * height;
 
1047
                vpic = upic + (width * height) / 4;
 
1048
                row[0] = (unsigned char *) line;
 
1049
                y = 0;
 
1050
                
 
1051
                while (cinfo.output_scanline < height) {
 
1052
                        jpeg_read_scanlines(&cinfo, row, 1);
 
1053
                        for (i = 0; i < line_size; i += 3) {
 
1054
                                pic[i / 3] = ((unsigned char *) line)[i];
 
1055
                                if (i & 1) {
 
1056
                                        upic[(i / 3) / 2] = ((unsigned char *) line)[i + 1];
 
1057
                                        vpic[(i / 3) / 2] = ((unsigned char *) line)[i + 2];
 
1058
                                }
 
1059
                        }
 
1060
                        pic += line_size / 3;
 
1061
                        if (y++ & 1) {
 
1062
                                upic += width / 2;
 
1063
                                vpic += width / 2;
 
1064
                        }
 
1065
                }
 
1066
                
 
1067
                jpeg_finish_decompress(&cinfo);
 
1068
                jpeg_destroy_decompress(&cinfo);
 
1069
                
 
1070
                if(cnt->rotate_data.degrees > 0) {
 
1071
                        /* rotate as specified */
 
1072
                        rotate_map(image, cnt);
 
1073
                }
 
1074
        } else {
 
1075
                fprintf(stderr,"Netcam netcam_next(): thread %d: Image size %d\n",netcam->threadnr, (int)netcam->image[netcam->which_image].size);
 
1076
                pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
1077
                if (netcam->image[0].buffer) free(netcam->image[0].buffer);
 
1078
                if (netcam->image[1].buffer) free(netcam->image[1].buffer);
 
1079
                if ((cnt->conf.netcam_userpass) && (netcam->userpass)) free(netcam->userpass);
 
1080
                if (netcam->boundary_string) free(netcam->boundary_string);
 
1081
                if (netcam->url.host) free(netcam->url.host);
 
1082
                if (netcam->url.path) free(netcam->url.path);
 
1083
                if (netcam->response) free(netcam->response);
 
1084
                if (netcam) free(netcam);
 
1085
                return NULL;
 
1086
        }
 
1087
        pthread_mutex_unlock(&netcam->image[which_image].mutex);
 
1088
        
 
1089
        return pic;
 
1090
}