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'.
15
#include "video_freebsd.h"
18
#endif /* __freebsd__ */
21
#include <netinet/in.h>
22
#include <sys/types.h>
23
#include <sys/socket.h>
29
#include "netcam_wget.h"
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"
36
struct jpeg_source_mgr pub;
40
boolean start_of_file;
43
typedef my_source_mgr *my_src_ptr;
46
struct jpeg_error_mgr pub;
47
jmp_buf setjmp_buffer;
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);
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);
70
int netcam_start(struct context *);
71
unsigned char *netcam_next(struct context *, char *);
77
int netcam_parse_url (struct url_t *parse_url, char *text_url)
83
dup = strdup(text_url);
85
parse_url->service = NULL;
86
parse_url->host = NULL;
88
parse_url->path = NULL;
90
if ((p = strstr (parse, ":/"))) {
92
if (p[0] == '/' && p[1] == '/') p += 2;
93
parse_url->service = strdup (dup);
97
p = strchr (parse, '/');
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, ':');
108
p2 = strchr (parse_url->host, ':');
112
parse_url->port = atoi (p2);
116
if (parse) parse_url->path = strdup (parse);
118
free(parse_url->service);
128
overrided by own init_source routine.
129
Initialize source --- called by jpeg_read_header
130
before any data is actually read.
133
void my_init_source (j_decompress_ptr cinfo)
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.
140
src->start_of_file = TRUE;
144
jpeglib fill_input_buffer
146
override by own fill_input_buffer routine.
147
Fill the input buffer --- called whenever buffer is emptied
150
boolean my_fill_input_buffer (j_decompress_ptr cinfo)
152
my_src_ptr src = (my_src_ptr) cinfo->src;
155
if (src->start_of_file) {
157
src->buffer=src->data;
159
// Insert a fake EOI marker - as per jpeglib recommendation
160
src->buffer[0] = (JOCTET) 0xFF;
161
src->buffer[1] = (JOCTET) JPEG_EOI; // 0xD9
165
src->pub.next_input_byte = src->buffer;
166
src->pub.bytes_in_buffer = nbytes;
167
src->start_of_file = FALSE;
173
jpeglib skip_input_data
175
override by own skip_input_data routine.
176
Skip data --- used to skip over a potentially large amount of
180
void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
182
my_src_ptr src = (my_src_ptr) cinfo->src;
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);
189
src->pub.next_input_byte += (size_t) num_bytes;
190
src->pub.bytes_in_buffer -= (size_t) num_bytes;
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
203
void my_term_source (j_decompress_ptr cinfo) { }
208
Prepare for input from memory .
209
The caller must have already allocated memory, and is responsible
210
for freed it after finishing decompression.
213
void jpeg_memory_src(j_decompress_ptr cinfo, char *data, int length)
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;
223
src = (my_src_ptr) cinfo->src;
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;
239
overrided by our own error_exit routine.
240
Triggered when a fatal error occurs.
243
void my_error_exit (j_common_ptr cinfo)
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);
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
256
If JPEG start or end are incorrect or connection error returns -1
259
int netcam_check_JPEG(struct netcam_context *netcam, int which_image, int connection){
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);
268
else if (!memmem(&netcam->image[which_image].buffer[netcam->image[which_image].size -2],
270
fprintf(stderr,"Netcam thread %d : Error checking JPEG not end code \n",netcam->threadnr);
277
if (netcam_connect(netcam) != 0) return -1;
280
if (netcam->content_length) ret = netcam_read_header(netcam, 0);
281
else ret = netcam_read_header(netcam, 2);
292
static void *netcam_loop(void *arg)
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());
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);
302
} while (!cnt->finish);
305
pthread_mutex_lock(&cnt->netcam->image[0].mutex);
306
pthread_mutex_lock(&cnt->netcam->image[1].mutex);
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);
317
pthread_mutex_unlock(&cnt->netcam->image[0].mutex);
318
pthread_mutex_unlock(&cnt->netcam->image[1].mutex);
320
fprintf(stderr, "Netcam: thread %d: Exiting\n",cnt->netcam->threadnr);
321
if (cnt->netcam) free(cnt->netcam);
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".
332
On Error Return -1 Header Uknown
337
int netcam_read_header(struct netcam_context *netcam, int initial)
339
char *header,*conttype;
343
status = header_get (netcam->response, &header, HG_NONE);
345
if (status == HG_ERROR) {
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);
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);
360
if (hcount == 0 && initial == 1) {
361
/* process http ok ... or any other error header response */
362
fprintf(stderr,"[%s]\n",header);
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) ))
371
if (strcmp("multipart/x-mixed-replace", conttype) == 0) {
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=")) ) {
377
netcam->boundary_string = strdup(bound);
378
fprintf(stderr, "Netcam: thread %d: netcam->boundary_string [%s]\n", netcam->threadnr, netcam->boundary_string);
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;
385
syslog(LOG_ERR, "Netcam: thread %d: unknown Content-Type", netcam->threadnr);
386
fprintf (stderr,"Netcam: thread %d: unknown Content-Type\n", netcam->threadnr);
390
if (conttype) free(conttype);
391
} else if (!*header) {
404
Establish netcam connection , it has a 5 seconds timeout
409
int netcam_connect(struct netcam_context *netcam)
412
struct sockaddr_in server;
413
struct hostent *host_info;
417
sock = socket(PF_INET, SOCK_STREAM, 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));
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);
433
memcpy((char *) &server.sin_addr, host_info->h_addr, host_info->h_length);
435
server.sin_family = AF_INET;
436
server.sin_port = htons(netcam->url.port);
438
/* 5 seconds timeout */
441
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
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);
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);
454
request = (char *) mymalloc(strlen(REQUEST) +
455
strlen(netcam->url.path) + 1);
456
sprintf(request, REQUEST, netcam->url.path);
459
rbuf_initialize(netcam->response, sock);
461
send(RBUF_FD(netcam->response), request, strlen(request), 0);
469
Close netcam connection , only for single image.
471
int netcam_close(struct netcam_context *netcam)
473
if (netcam->response->fd == -1) return 0;
474
close(RBUF_FD(netcam->response));
475
netcam->response->fd = -1;
481
Try to reconnect to the stream and get a frame
486
int netcam_stream_reconnection(struct netcam_context *netcam,int which_image)
488
int ret=-1,num_errors=-1;
490
netcam_close(netcam);
492
if (netcam->boundary_string) {
493
free(netcam->boundary_string);
494
netcam->boundary_string=NULL;
497
netcam->content_length=0;
499
while ((netcam_connect(netcam) == -1) && (num_errors < 10)) {
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);
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);
511
ret = netcam_read_header(netcam, 1);
515
if (netcam->content_length)
516
ret = netcam_read_header(netcam, 0);
518
ret = netcam_read_header(netcam, 2);
521
if (netcam->content_length)
522
ret = netcam_read_image(netcam);
524
ret = netcam_read_stream_no_content_length(netcam,which_image);
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);
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);
543
Content-Type: image/jpeg^M
546
Content-Type: image/jpeg^M
550
netcam stream read function for Non Content-Length support devices.
554
int netcam_read_stream_no_content_length(struct netcam_context *netcam,int which_image)
556
int cur_size=0,readb=0;
557
size_t boundary_string_length;
558
char *pointer_boundary=NULL,*pointer_init=NULL;
562
cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer,100000);
563
boundary_string_length = strlen(netcam->boundary_string);
566
Get the image until find jpeg header ( JFIF v3 )
569
// Get the init of the image
571
pointer_init = memmem(netcam->image[which_image].buffer,cur_size,"\xFF\xD8\xFF",3);
573
int init_read=0,end_read=0;
574
init_read = pointer_init - netcam->image[which_image].buffer;
576
end_read = cur_size - init_read;
577
memmove(netcam->image[which_image].buffer,&netcam->image[which_image].buffer[init_read],end_read);
583
while (!pointer_init){
584
readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
586
pointer_init = memmem(netcam->image[which_image].buffer,cur_size,"\xFF\xD8\xFF",3);
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);
599
* Get the image until find the next STREAM HEADER
603
readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
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));
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;
614
} while (!pointer_boundary);
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;
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;
631
netcam image read function for Non Content-Length support devices
635
int netcam_read_image_no_content_length(struct netcam_context *netcam,int which_image)
641
cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer, 100000);
644
readb = read(netcam->response->fd, &netcam->image[which_image].buffer[cur_size], 4096);
646
} while ((readb > 0) && (cur_size < 100000));
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));
653
netcam->image[which_image].buffer_size = cur_size;
654
netcam->image[which_image].size = cur_size;
661
netcam stream/image read function for Content-Length support devices
665
int netcam_read_image(struct netcam_context *netcam)
667
int which_image,cur_size,cur_left;
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");
677
cur_size = rbuf_flush(netcam->response, netcam->image[which_image].buffer,
678
netcam->image[which_image].buffer_size);
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);
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;
689
cur_size += cur_left;
696
netcam image read function
700
int netcam_single_read(struct netcam_context *netcam,int initial)
702
int which_image,ret,num_errors=-1;
704
if (initial) netcam_close(netcam);
706
while (netcam_connect(netcam) == -1) {
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);
719
pthread_mutex_lock(&netcam->mutex);
720
which_image = netcam->which_image = !netcam->which_image;
721
pthread_mutex_unlock(&netcam->mutex);
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);
730
fprintf(stderr,"Netcam single: thread %d : Content-length NO supported \n", netcam->threadnr);
734
ret = netcam_read_header(netcam, 0);
738
pthread_mutex_lock(&netcam->image[which_image].mutex);
740
if (netcam->content_length)
741
ret = netcam_read_image(netcam);
743
ret = netcam_read_image_no_content_length(netcam,which_image);
744
netcam_close(netcam);
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);
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);
760
netcam_close(netcam);
763
pthread_mutex_unlock(&netcam->image[which_image].mutex);
769
netcam stream read function
770
On Success returns 1 <- !?
773
int netcam_stream_read(struct netcam_context *netcam,int initial)
775
int which_image,ret,num_errors=-1;
777
pthread_mutex_lock(&netcam->mutex);
778
which_image = netcam->which_image = !netcam->which_image;
779
pthread_mutex_unlock(&netcam->mutex);
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);
788
fprintf(stderr,"Netcam stream : thread %d: Content-length NO supported \n", netcam->threadnr);
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);
800
if (netcam->content_length)
801
ret = netcam_read_header(netcam, 0);
803
ret = netcam_read_header(netcam, 2);
807
pthread_mutex_lock(&netcam->image[which_image].mutex);
810
if (netcam->content_length)
811
ret = netcam_read_image(netcam);
813
ret = netcam_read_stream_no_content_length(netcam,which_image);
817
} while ( ((netcam_check_JPEG(netcam,which_image,0)) == -1) && (num_errors < 10));
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);
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);
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);
842
netcam init called function , it establishes connection to network device, gets
843
the image or the stream and creates the read thread.
846
int netcam_start(struct context *cnt)
848
struct jpeg_decompress_struct cinfo;
849
struct jpeg_error_mgr jerr;
850
pthread_attr_t thread_attr;
852
struct netcam_context *netcam;
855
syslog(LOG_INFO, "Netcam: thread %d: starting...", cnt->threadnr);
856
fprintf(stderr,"Netcam: thread %d: starting...\n", cnt->threadnr);
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;
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;
874
netcam_parse_url (&netcam->url, cnt->conf.netcam_url);
876
if (cnt->conf.netcam_userpass) {
877
netcam->userpass = (char *) mymalloc(BASE64_LENGTH(strlen(cnt->conf.netcam_userpass))+1);
879
char *userpass=mymalloc(strlen(cnt->conf.netcam_userpass)+4);
880
/* base64_encode can read 3 bytes after the end of the string,
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));
889
netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf));
892
image buffer should be set for Non Content-Length support devices.
893
FIXME : Maybe it should not be hardcoded here !?
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;
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);
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);
929
/* Call to fetch image or stream function */
930
netcam->read(netcam,1);
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);
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;
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);
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);
968
netcam process image function , is called by motion thread to get an image
969
from netcam read thread.
972
unsigned char *netcam_next(struct context *cnt, char *image)
974
struct jpeg_decompress_struct cinfo;
975
struct my_error_mgr jerr;
976
unsigned char *pic, *upic, *vpic;
978
int i, line_size, y,which_image,ret;
980
int width, height; /* for rotation */
981
struct netcam_context *netcam;
985
netcam = cnt->netcam;
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);
993
pthread_mutex_lock(&netcam->image[which_image].mutex);
995
while ((!netcam->image[which_image].filled) && (!cnt->finish)) {
996
memset(&now, 0, sizeof now);
997
now.tv_sec=time(0)+5;
999
ret = pthread_cond_timedwait(&netcam->image[which_image].buffer_filled,&netcam->image[which_image].mutex,
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);
1006
/* success condition */
1013
pthread_mutex_unlock(&netcam->image[which_image].mutex);
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;
1022
if (setjmp(jerr.setjmp_buffer)) {
1023
jpeg_destroy_decompress(&cinfo);
1024
pthread_mutex_unlock(&netcam->image[which_image].mutex);
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);
1032
cinfo.out_color_space = JCS_YCbCr;
1034
/* NOTE: Since this is a capture, we need to use the capture dimensions. */
1035
/* POSSIBLE BUG: What if the netcam changes resolution? */
1037
width = cnt->rotate_data.cap_width;
1038
height = cnt->rotate_data.cap_height;
1040
jpeg_start_decompress(&cinfo);
1041
line_size = width * 3;
1043
line = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo,
1044
JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
1046
upic = pic + width * height;
1047
vpic = upic + (width * height) / 4;
1048
row[0] = (unsigned char *) line;
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];
1056
upic[(i / 3) / 2] = ((unsigned char *) line)[i + 1];
1057
vpic[(i / 3) / 2] = ((unsigned char *) line)[i + 2];
1060
pic += line_size / 3;
1067
jpeg_finish_decompress(&cinfo);
1068
jpeg_destroy_decompress(&cinfo);
1070
if(cnt->rotate_data.degrees > 0) {
1071
/* rotate as specified */
1072
rotate_map(image, cnt);
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);
1087
pthread_mutex_unlock(&netcam->image[which_image].mutex);