00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <stdint.h>
00025 #include <string.h>
00026 #include <getopt.h>
00027 #include <time.h>
00028 #include <sys/time.h>
00029 #include <sys/types.h>
00030 #include <sys/ioctl.h>
00031 #include <sys/mman.h>
00032 #include <fcntl.h>
00033 #include <unistd.h>
00034 #include <limits.h>
00035 #include <math.h>
00036 #include <netinet/in.h>
00037 #include <pthread.h>
00038 #include <sched.h>
00039 #include <errno.h>
00040
00041 #include <sys/socket.h>
00042 #include <netinet/in.h>
00043 #include <arpa/inet.h>
00044 #include <netpacket/packet.h>
00045 #include <net/ethernet.h>
00046
00047 #include "str.h"
00048 #include "net_udp.h"
00049 #include "rtp.h"
00050 #include <asm/elphel/c313a.h>
00051 #include <asm/elphel/hist.h>
00052 #include "event.h"
00053 #include "rtsp.h"
00054
00055 #define RTP_PAYLOAD_SIZE 1460
00056 #define JPEG_RTP_HDR_SIZE 8
00057
00058 #define MMAP_METHOD 1
00059 #define READ_METHOD 2
00060
00061 #define SDP_FILE "/var/html/session.sdp"
00062 #define SESSION_DESCR "Elphel camera 353"
00063
00064 #define PROGR_PARAM 1
00065 #define DEFAULT_DEST_IP "232.1.1.1"
00066 #define DEFAULT_DEST_PORT 20020
00067 #define DEFAULT_RTSP_PORT 554
00068 #define DEFAULT_TTL 2
00069 #define DEFAULT_REFRESH_INTERVAL 5
00070
00071 #define RTSP_ON_TAG 10
00072 #define RTSP_OFF_TAG 11
00073 #define RTSP_LISTEN_PORT_TAG 12
00074 #define RTSP_USE_OPT_ADDR_TAG 13
00075 #define RTSP_USE_OPT_PORT_TAG 14
00076 #define RTSP_QT_COMPAT_TAG 15
00077
00078 #define FRESH_FILE "/var/html/fresh.jpeg"
00079 #define HDR_SIZE 623
00080 #define TMP_BUF_OFFS 0xfe000
00081 #define YUV420 1
00082 #define MAX_JPEG_BUF 2000000
00083 #define HZ 10000
00084
00085 #define NO_IOCTLS_IN_CIRCBUF y
00086 int8_t version[] = "1.7";
00087
00088 static int8_t *header =
00089 "RTP/JPEG streamer for Elphel 333/353 camera\n"
00090 "Version %s\n"
00091 " (C) Elphel, Inc\n"
00092 " 2004 Alexander Melichenko <alexlp@freemail.ru>\n"
00093 " 2007 Mykhailo Malyshko aka Spectr\n"
00094 "\n";
00095
00096
00097 const uint64_t TimestampTicks = 1000000;
00098 int32_t fd;
00100 int32_t ioctl_fd;
00101
00102
00103 inline uint64_t GetTimestamp(uint32_t tv_sec, uint32_t tv_usec) {
00104 return ((uint64_t) tv_sec * TimestampTicks) + tv_usec;
00105 }
00106
00107 inline uint32_t ts2rtp(struct param * p, uint64_t t) {
00108 if(p->start_timestamp) {
00109 return (uint32_t) (((t - p->start_timestamp) * p->vbitrt) / TimestampTicks);
00110 }
00111 p->start_timestamp = t;
00112 return 0;
00113 }
00114
00115
00116
00117
00118
00119
00120 int8_t write_sdp(struct param * p, int save, int8_t *sdp) {
00121 FILE *f = NULL;
00122 struct timeval tv;
00123 uint64_t session_id, version;
00124 int8_t var[256];
00125 int32_t count;
00126 int32_t port;
00127 int8_t *dst, dst_d[]="0.0.0.0";
00128 double fps = 0;
00129 int w, h;
00130
00131
00132 fps = 0.01 * ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_FP100S), 0);
00133 w = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_ACTUAL_WIDTH), 0);
00134 h = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_ACTUAL_HEIGHT), 0);
00135
00136 if(save){
00137 f = fopen(SDP_FILE, "w");
00138 if (!f) {
00139 fprintf(stderr, "SDP file creating error!");
00140 return -1;
00141 }
00142 }
00143
00144 count = 0;
00145 memset(var, 0, 256);
00146 sprintf(var, "v=0\n");
00147 strcpy(sdp+count, var);
00148 count += strlen(var);
00149
00150 gettimeofday(&tv, NULL);
00151 session_id = (uint64_t) tv.tv_sec * 1000000 + tv.tv_usec;
00152 gettimeofday(&tv, NULL);
00153 version = (uint64_t) tv.tv_sec * 1000000 + tv.tv_usec;
00154
00155 memset(var, 0, 256);
00156 sprintf(var, "o=- %lld %lld IN IP4 %s\n", session_id, version, p->src);
00157 strcpy(sdp+count, var);
00158 count += strlen(var);
00159
00160 if(p->rtsp && !p->rtsp_use_cmd_port && str_count < 1){
00161 port = 0;
00162 } else {
00163 port = p->dport;
00164 }
00165
00166 if(p->rtsp && !p->rtsp_use_cmd_addr && str_count < 1){
00167 dst = dst_d;
00168 } else {
00169 dst = p->dst;
00170 }
00171
00172 memset(var, 0, 256);
00173 sprintf(var, "s=%s\n"
00174 "m=video %d RTP/AVP %d\n"
00175 "c=IN IP4 %s", SESSION_DESCR, port,
00176 JPEG_PAYLOAD_NUM, dst);
00177 strcpy(sdp+count, var);
00178 count += strlen(var);
00179
00180 if (ismulticast(p) && (p->rtsp && p->rtsp_use_cmd_addr)){
00181 memset(var, 0, 256);
00182 sprintf(var, "/%d", p->ttl);
00183 strcpy(sdp+count, var);
00184 count += strlen(var);
00185 }
00186
00187 memset(var, 0, 256);
00188 sprintf(var, "\n");
00189 strcpy(sdp+count, var);
00190 count += strlen(var);
00191
00192 if(p->rtsp){
00193 memset(var, 0, 256);
00194 sprintf(var, "a=control:rtsp://%s:%d\na=control:track1\n",
00195 p->src, p->rtsp_port);
00196 strcpy(sdp+count, var);
00197 count += strlen(var);
00198 }
00199
00200 if((p->fps_soft > 0) && (p->fps_soft <= p->fps)){
00201 fps = (double) p->fps_soft;
00202 }
00203
00204 memset(var, 0, 256);
00205 sprintf(var, "a=x-framerate:%.2f\n", fps);
00206 strcpy(sdp+count, var);
00207 count += strlen(var);
00208
00209 memset(var, 0, 256);
00210 sprintf(var, "a=framerate:%.2f\n", fps);
00211 strcpy(sdp+count, var);
00212 count += strlen(var);
00213
00214
00215
00216 memset(var, 0, 256);
00217 sprintf(var, "a=x-width:%d\n", w);
00218 strcpy(sdp+count, var);
00219 count += strlen(var);
00220 memset(var, 0, 256);
00221 sprintf(var, "a=width:%d\n", w);
00222 strcpy(sdp+count, var);
00223 count += strlen(var);
00224
00225
00226
00227 memset(var, 0, 256);
00228 sprintf(var, "a=x-height:%d\n", h);
00229 strcpy(sdp+count, var);
00230 count += strlen(var);
00231 memset(var, 0, 256);
00232 sprintf(var, "a=height:%d\n", h);
00233 strcpy(sdp+count, var);
00234 count += strlen(var);
00235
00236 memset(var, 0, 256);
00237 sprintf(var, "a=x-dimensions:%d,%d\n", w, h);
00238 strcpy(sdp+count, var);
00239 count += strlen(var);
00240
00241
00242 sdp[count] = 0;
00243
00244 if(save){
00245 fprintf(f, "%s", sdp);
00246 fclose(f);
00247 fflush(NULL);
00248 }
00249
00250 return 0;
00251 }
00252
00253 void session_finish(struct param *p) {
00254 rtp_done(p);
00255 fprintf(stderr, "\nSession %#x finished...\n", p->my_ssrc);
00256 }
00257
00258 int32_t jpeg_session_start(struct param *p) {
00259 int32_t q = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_QUALITY), 0);
00260 int32_t ism = 0;
00261 int32_t res;
00262
00263 p->payload_num = JPEG_PAYLOAD_NUM;
00264 p->start_timestamp = 0;
00265
00266 res = rtp_init(p);
00267 if(res != 0) {
00268 fprintf(stderr, "Couldn't start rtp session\n");
00269 return -1;
00270 }
00271
00272 ism = ismulticast(p);
00273 fprintf(stderr, header, version);
00274 if(p->rtsp) {
00275 fprintf(stderr, "\tRTSP server is listening on the port %d.\n", p->rtsp_port);
00276 if(!p->rtsp_use_cmd_addr) {
00277 fprintf(stderr, "\tDestination address will got from rtsp request.\n");
00278 }
00279 if(!p->rtsp_use_cmd_port) {
00280 fprintf(stderr, "\tDestination port will got from rtsp request.\n");
00281 }
00282 fprintf(stderr, "\n\tStream is accessible by uri rtsp://%s:%d\n", p->src, p->rtsp_port);
00283 }
00284
00285 fprintf(stderr, "\nSession %#x started...\n", p->my_ssrc);
00286
00287 if(p->web > 0) {
00288 fprintf(stderr, "\tWeb camera mode enabled. Refresh time - %d second\n", p->web);
00289 }
00290 if(p->meth == READ_METHOD) {
00291 fprintf(stderr, "\tAccess method READ\n");
00292 } else {
00293 fprintf(stderr, "\tAccess method MMAP\n");
00294 }
00295 if(p->zero) {
00296 fprintf(stderr, "\tVideo streaming disabled\n");
00297 fprintf(stderr,
00298 "\twidth = %d\n"
00299 "\theight = %d\n"
00300 "\tquality = %d\n"
00301 "\tFPS = %.2f\n", p->width, p->height, q, p->fps);
00302 return 0;
00303 }
00304 fprintf(stderr, "\tmode = ");
00305 if(ism)
00306 fprintf(stderr, "multicast ");
00307 else
00308 fprintf(stderr, "unicast ");
00309 if(p->raw)
00310 fprintf(stderr, "by-passing UDP/IP stack\n");
00311 else
00312 fprintf(stderr, "using UDP/IP stack\n");
00313 fprintf(stderr, "\tdest_addr = %s\n", p->dst);
00314 if(ism)
00315 fprintf(stderr, "\tttl = %d\n", p->ttl);
00316 fprintf(stderr,
00317 "\tdest_port = %d\n"
00318 "\twidth = %d\n"
00319 "\theight = %d\n"
00320 "\tquality = %d\n"
00321 "\tSystem FPS = %.2f\n"
00322 "\tSoft FPS = %d\n",
00323 p->dport, p->width, p->height, q, p->fps, p->fps_soft);
00324
00325
00326 if(p->raw) {
00327 if(p->fd_raw == 0)
00328 p->fd_raw = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
00329
00330 struct sockaddr_in s_in;
00331
00332 memset(&p->s_ll, 0, sizeof(p->s_ll));
00333
00334 p->s_ll.sll_family = AF_PACKET;
00335 p->s_ll.sll_protocol = htons(ETH_P_IP);
00336 p->s_ll.sll_ifindex = p->eth_index;
00337 p->s_ll.sll_halen = ETH_ALEN;
00338
00339 if(ismulticast(p)){
00340
00341 memcpy(p->s_ll.sll_addr, "\x01\x00\x5e", 3);
00342 unsigned char a[3];
00343 unsigned int _a;
00344 _a = inet_addr(p->dst);
00345 a[0] = (_a >> 8) & 0x7F;
00346 a[1] = (_a >> 16) & 0xFF;
00347 a[2] = (_a >> 24) & 0xFF;
00348 memcpy(p->s_ll.sll_addr + 3, a, 3);
00349
00350 struct ip_mreqn multiaddr;
00351 multiaddr.imr_multiaddr.s_addr = inet_addr(p->dst);
00352 multiaddr.imr_address.s_addr = htonl(INADDR_ANY);
00353 multiaddr.imr_ifindex = 0;
00354 setsockopt(p->fd_raw, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multiaddr, sizeof(struct sockaddr_in));
00355 } else {
00356 memcpy(p->s_ll.sll_addr, p->dst_mac, 6);
00357 }
00358
00359 p->msg.msg_control = 0;
00360 p->msg.msg_flags = 0;
00361 p->msg.msg_name = (void *)&p->s_ll;
00362 p->msg.msg_namelen = sizeof(p->s_ll);
00363
00364
00365
00366 } else {
00367 if(p->fd_udp == 0)
00368 p->fd_udp = socket(PF_INET, SOCK_DGRAM, 0);
00369 struct sockaddr_in addr;
00370 addr.sin_addr.s_addr = inet_addr(p->dst);
00371 addr.sin_port = htons(p->dport);;
00372 addr.sin_family = AF_INET;
00373
00374 connect(p->fd_udp, (struct sockaddr *)&addr, sizeof(struct sockaddr));
00375 }
00376
00377 return 0;
00378 }
00379
00380 int32_t send_jpeg(struct param *p, uint8_t * _data, uint32_t sz,
00381 uint32_t max_size, uint8_t type, uint8_t q, uint32_t t_sec, uint32_t t_usec)
00382 {
00383 uint32_t size = sz + 2;
00384 uint32_t offset = 0;
00385
00386 uint8_t *dt = _data;
00387 int32_t ret;
00388 uint32_t rtpTimestamp = ts2rtp(p, GetTimestamp(t_sec, t_usec));
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 if(max_size > RTP_PAYLOAD_SIZE) {
00400 fprintf(stderr, "Max rtp size couldn't be more then %d\n", RTP_PAYLOAD_SIZE);
00401 return -1;
00402 }
00403
00404 uint8_t h[128];
00405 int h_offset = 96;
00406
00407 dt += 8 + 12;
00408 if(p->raw)
00409 dt += 28;
00410
00411 h[h_offset + 0] = 0;
00412 h[h_offset + 1] = 0;
00413 h[h_offset + 2] = 0;
00414 h[h_offset + 3] = 0;
00415 h[h_offset + 4] = type;
00416 h[h_offset + 5] = q;
00417 if(p->width <= 2040)
00418 h[h_offset + 6] = p->width / 8;
00419 else
00420 h[h_offset + 6] = 0;
00421 if(p->height <= 2040)
00422 h[h_offset + 7] = p->height / 8;
00423 else
00424 h[h_offset + 7] = 0;
00425 max_size -= JPEG_RTP_HDR_SIZE;
00426 max_size -= 32;
00427
00428 uint32_t payloadLength = max_size;
00429 int32_t lastPacket = 0;
00430 while(size) {
00431 if(size <= max_size) {
00432 payloadLength = size;
00433 lastPacket = 1;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 ret = rtp_send_data(p, rtpTimestamp, p->payload_num, lastPacket, dt, payloadLength, (unsigned char *)h, h_offset, 8);
00446
00447 dt += payloadLength;
00448
00449 offset += payloadLength;
00450 size -= payloadLength;
00451 h[h_offset + 0] = 0;
00452 h[h_offset + 1] = offset >> 16;
00453 h[h_offset + 2] = offset >> 8;
00454 h[h_offset + 3] = offset;
00455 h[h_offset + 4] = type;
00456 h[h_offset + 5] = q;
00457 if(p->width <= 2040)
00458 h[h_offset + 6] = p->width / 8;
00459 else
00460 h[h_offset + 6] = 0;
00461 if(p->height <= 2040)
00462 h[h_offset + 7] = p->height / 8;
00463 else
00464 h[h_offset + 7] = 0;
00465
00466
00467 }
00468
00469 return 0;
00470 }
00471
00472
00473 void usage(struct param *p, int32_t ret)
00474 {
00475 static int8_t *usage =
00476 "Usage: %s [options]\n"
00477 "Options:\n"
00478 "\t-a --addr xx.xx.xx.xx - multicast destination address\n"
00479 "\t by default == %s\n"
00480 "\t (must be from 224.0.0.0 to 239.255.255.255)\n"
00481 "\t-p --port xx - port, destination for multicast, and source for unicast/multicast\n"
00482 "\t by default == %d\n"
00483 "\t-t --ttl xx - TTL (Time-To-Live for multicast, default %d)\n"
00484 "\t-s --silent - \"silent\" mode for multicast - wait client over RTSP for streaming\n"
00485 "\t (w/o this option - send multicast stream all time - by default)\n"
00486 "\t-m --mcast - send stream over multicast\n"
00487 "\t-u --ucast - send stream over unicast (used by default)\n"
00488 "\t in unicast mode supported only one active RTSP client\n"
00489 "\t-f --fps xx.xx - use fixed FPS for stream\n"
00490 "\n";
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551 fprintf(stderr, header, version);
00552 fprintf(stderr, usage, p->program_name, DEFAULT_DEST_IP,
00553 DEFAULT_DEST_PORT, DEFAULT_TTL);
00554
00555
00556 exit(ret);
00557 }
00558
00559 void opt_parse(int32_t argc, char *const argv[], struct param *p)
00560 {
00561 uint32_t var;
00562 int32_t next;
00563 const struct option long_opt[] = {
00564 {"addr", 1, NULL, 'a'},
00565 {"port", 1, NULL, 'p'},
00566 {"ttl", 1, NULL, 't'},
00567 {"silent", 0, NULL, 's'},
00568 {"mcast", 0, NULL, 'm'},
00569 {"ucast", 0, NULL, 'u'},
00570 {"fps", 1, NULL, 'f'},
00571 {NULL, 0, NULL, 0 }
00572 };
00573 const int8_t *const short_opt = "a:p:t:smuf:";
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599 int mcast = 0;
00600 int silent = 0;
00601 float fps = 0;
00602
00603 p->program_name = strdup(argv[0]);
00604
00605 if(argc < PROGR_PARAM)
00606 usage(p, 0);
00607
00608 do {
00609 next = getopt_long(argc, argv, short_opt, long_opt, NULL);
00610 switch(next) {
00611 case '?':
00612 case 'h':
00613 usage(p, 0);
00614 break;
00615 case 'a':
00616 p->dst = optarg;
00617 mcast = 1;
00618 break;
00619 case 'p':
00620 var = strtoul(optarg, (char **)NULL, 10);
00621 if((var > 65535) || (var <= 0)) {
00622 fprintf(stderr, "ERROR: destination RTP port is not correct\n\n");
00623 goto error;
00624 }
00625 p->dport = (uint16_t)var;
00626 if(p->dport % 2) {
00627 fprintf(stderr, "\nERROR: destination RTP port cann't be odd\n\n");
00628 goto error;
00629 }
00630 break;
00631 case 't':
00632 var = strtoul(optarg, (char **) NULL, 10);
00633 if((var > 255) || (var <= 0)) {
00634 fprintf(stderr, "ERROR: TTL is not correct\n\n");
00635 goto error;
00636 }
00637 p->ttl = (uint16_t) var;
00638 break;
00639 case 'f':
00640 fps = atof(optarg);
00641 if(fps < 0)
00642 fps = 0;
00643 if(fps > 250)
00644 fps = 250;
00645 p->hw_fps = 100 * fps;
00646 break;
00647 case 's':
00648 silent = 1;
00649 break;
00650 case 'u':
00651 mcast = 0;
00652 break;
00653 case 'm':
00654 mcast = 1;
00655 break;
00656 case -1:
00657 break;
00658 default:
00659 usage(p, 1);
00660 break;
00661 }
00662 } while(next != -1);
00663
00664 if(mcast) {
00665 p->rtsp_use_cmd_addr = 1;
00666 p->rtsp_use_cmd_port = 1;
00667 p->rtsp_qt_compat = 1;
00668 }
00669
00670
00671 next = optind;
00672
00673 return;
00674 error:
00675 exit(-1);
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 if(mcast) {
00779 p->rtsp_use_cmd_addr = 1;
00780 p->rtsp_use_cmd_port = 1;
00781 p->rtsp_qt_compat = 1;
00782 }
00783 next = optind;
00784 }
00785
00786 int32_t buf_size;
00787 int32_t str_setup;
00788 int32_t str_play;
00789 int32_t str_teardown;
00790 int32_t str_stop;
00791 int32_t str_count;
00792 int8_t *wbuf;
00793 unsigned long *start, *ccam_dma_buf;
00794
00795 int32_t grab_and_send(struct param *p)
00796 {
00797 int32_t status = 0, res, res_buf;
00798 int32_t offs;
00799 int32_t alen, jpeg_wp, old_jpeg_wp = 0, frame;
00800 int32_t ret, count, fr_fd = -1;
00801 int32_t all_buf_sz;
00802 int32_t stack_offs = 0, cnt = 0, buf_len = 0;
00803 uint8_t q = 0;
00804 uint8_t jpeg_type = YUV420;
00805 uint32_t frame_avg = 0;
00806 uint32_t fps_dlt = 0, dlt;
00807 double _fps, bw, tm;
00808 struct timeval st, ft, fps_st, fps_fn;
00809 time_t cur_time;
00810 static time_t old_time = 0;
00811 int8_t *buf, sdp[8192];
00812 static int32_t run_flag = 0;
00813
00814 struct timeval tv;
00815
00816 if(run_flag && p->rtsp && p->rtsp_qt_compat) {
00817 goto run_flag1;
00818 }
00819 run_flag = 1;
00820
00821 if(p->fps_soft > 0) {
00822 fps_dlt = 1000000 / p->fps_soft;
00823 }
00824
00825 status = ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_MONITOR_SEQ), 0);
00826 if((status == CAMSEQ_RUN || status == CAMSEQ_SINGLE) && p->meth == READ_METHOD) {
00827 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_STOP);
00828 }
00829
00830 if(status != CAMSEQ_RUN && p->meth == MMAP_METHOD) {
00831 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_START);
00832 fprintf(stderr, "+++++++++++++++ Compressor start\n");
00833 }
00834
00835 if(p->meth == READ_METHOD) {
00836 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_CATCHUP);
00837 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_FORGET);
00838 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_ACQUIRE);
00839 }
00840
00841 run_flag1:
00842
00843 p->width = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_ACTUAL_WIDTH), 0);
00844 p->height = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_ACTUAL_HEIGHT), 0);
00845 p->fps = 0.01 * ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_FP100S), 0);
00846 p->vbitrt = 90000;
00847
00848 res = jpeg_session_start(p);
00849 if(res != 0) {
00850 fprintf(stderr, "Start session error!\n");
00851 return -1;
00852 }
00853
00854 memset(sdp, 0, 8192);
00855 res = write_sdp(p, 1, sdp);
00856
00857 if(p->raw)
00858 stack_offs += IP_UDP_SIZE;
00859
00860 while(!str_play && !str_stop && !str_teardown)
00861 sched_yield();
00862
00863
00864 gettimeofday(&st, NULL);
00865 gettimeofday(&fps_st, NULL);
00866 while (!str_stop && !str_teardown) {
00867 while(!str_play && !str_stop && !str_teardown)
00868 sched_yield();
00869
00870 if(str_stop || str_teardown)
00871 break;
00872 if(p->fps_soft > 0){
00873 while(1) {
00874 gettimeofday(&fps_fn, NULL);
00875 dlt = (fps_fn.tv_sec*1000000+fps_fn.tv_usec) - (fps_st.tv_sec*1000000+fps_st.tv_usec);
00876 if(dlt < fps_dlt){
00877 if(fps_dlt-dlt > HZ*2) {
00878 usleep(HZ);
00879 }
00880 continue;
00881 }
00882 gettimeofday(&fps_st, NULL);
00883 break;
00884 }
00885 }
00886
00887 offs = sizeof(rtp_packet) + JPEG_RTP_HDR_SIZE + stack_offs;
00888 if(p->meth == READ_METHOD) {
00889 while((lseek(fd, 0, SEEK_END) == 0));
00890 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_ACQUIRE);
00891 lseek(fd, 0, SEEK_SET);
00892 buf_len = 0;
00893 res_buf = 0;
00894 while((res_buf = read(fd, wbuf + offs, MAX_JPEG_BUF - 100 - res_buf)) > 0) {
00895 offs += res_buf;
00896 buf_len += res_buf;
00897 }
00898 buf = wbuf + HDR_SIZE;
00899 } else {
00900 jpeg_wp = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, G_CIRCBUFWP), 0)>>2;
00901 if(jpeg_wp == old_jpeg_wp)
00902 continue;
00903 old_jpeg_wp = jpeg_wp;
00904
00905 if(jpeg_wp & 0x7)
00906 continue;
00907 alen = jpeg_wp - 9;
00908 if(alen < 0)
00909 alen += (buf_size >> 2);
00910
00911 if((ccam_dma_buf[alen] & 0xff000000) != 0xff000000) {
00912 fprintf(stderr, "skip frame with signature: 0x%08X\n", (unsigned int)ccam_dma_buf[alen]);
00913 continue;
00914 }
00915 buf_len = ccam_dma_buf[alen] & 0x00ffffff;
00916 tv.tv_sec = ccam_dma_buf[alen - 2];
00917 tv.tv_usec = ccam_dma_buf[alen - 1];
00918
00919 if(buf_len > buf_size)
00920 continue;
00921
00922
00923 all_buf_sz = ((((buf_len + 3) >> 2) + 11) >> 3) << 3;
00924 frame = alen + 1 - all_buf_sz;
00925 if(frame < 0) {
00926 frame += buf_size >> 2;
00927 {
00928 int8_t *ptr;
00929 int32_t end_part, start_part = 0;
00930 end_part = (frame << 2) + buf_len - buf_size;
00931 if(end_part >= 0)
00932 start_part = buf_len - end_part;
00933 ptr = ((int8_t *) (start + (TMP_BUF_OFFS >> 2))) - start_part;
00934 memcpy(ptr, &ccam_dma_buf[frame], start_part);
00935 buf = (int8_t *) (start + (TMP_BUF_OFFS >> 2) - (offs >> 2)) - start_part;
00936 }
00937 } else {
00938 buf = (int8_t *) (start + (TMP_BUF_OFFS >> 2) + frame - (offs >> 2));
00939 }
00940 }
00941
00942 if(p->web > 0) {
00943 cur_time = time(NULL);
00944 if(cur_time - old_time >= p->web) {
00945 old_time = cur_time;
00946 fr_fd = open(FRESH_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
00947 if(fr_fd < 0) {
00948 fprintf(stderr, "Fresh JPEG file is not created!\n");
00949 fprintf(stderr, "You can't use WEB CAMERA mode.\n");
00950 p->web = 0;
00951 goto noweb;
00952 }
00953
00954 count = 0;
00955 while(count != buf_len) {
00956 offs = sizeof(rtp_packet) + JPEG_RTP_HDR_SIZE + stack_offs;
00957 ret = write(fr_fd, wbuf + offs + count, buf_len - count);
00958 if(ret < 0) {
00959 fprintf(stderr, "Fresh JPEG file is not created!\n");
00960 fprintf(stderr, "You can't use WEB CAMERA mode.\n");
00961 close(fr_fd);
00962 p->web = 0;
00963 goto noweb;
00964 }
00965 count += ret;
00966 }
00967 }
00968 close(fr_fd);
00969 }
00970 noweb:
00971 frame_avg += buf_len;
00972
00973 cnt++;
00974 if(!p->zero) {
00975 if(tv.tv_sec == 0 && tv.tv_usec == 0)
00976 gettimeofday(&tv, NULL);
00977 q = ioctl(ioctl_fd, _CCCMD(CCAM_RPARS, P_QUALITY), 0);
00978 send_jpeg(p, buf, buf_len, RTP_PAYLOAD_SIZE, jpeg_type, q, tv.tv_sec, tv.tv_usec);
00979 }
00980
00981 if(cnt == 100 && p->verbose && !p->zero) {
00982 gettimeofday(&ft, NULL);
00983 tm = (((double)((ft.tv_sec * 1000000 + ft.tv_usec) - (st.tv_sec * 1000000 + st.tv_usec))) / 1000000);
00984 _fps = 100 / tm;
00985 bw = frame_avg * 8 / tm / 1000000;
00986 frame_avg = frame_avg / 100;
00987 gettimeofday(&st, NULL);
00988 fprintf(stderr, "fps=%.2f avg_size=%d BW=%.1f Mb/s\n", _fps, frame_avg, bw);
00989 fflush(NULL);
00990 cnt = 0;
00991 frame_avg = 0;
00992 }
00993
00994 if(p->meth == READ_METHOD) {
00995 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_FORGET);
00996 }
00997 }
00998
00999 if(run_flag && p->rtsp && p->rtsp_qt_compat) {
01000 goto run_flag2;
01001 }
01002
01003 if(status == CAMSEQ_RUN || status == CAMSEQ_SINGLE) {
01004 status = ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_MONITOR_SEQ), 0);
01005 if(status != CAMSEQ_RUN && status != CAMSEQ_SINGLE) {
01006 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_START);
01007 }
01008 } else {
01009 ioctl(ioctl_fd, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_STOP);
01010 }
01011
01012 run_flag2:
01013
01014 session_finish(p);
01015 return 0;
01016 }
01017
01018
01019 void *rtsp_loop(void* var){
01020 struct param *p = (struct param *)var;
01021
01022 rtsp_listen(p);
01023 event_loop(0);
01024 str_stop = 1;
01025 sleep(2);
01026 pthread_exit(0);
01027 return 0;
01028 }
01029
01030 int main(int argc, char **argv) {
01031 int32_t res;
01032 int8_t *ccam_file = "/dev/ccam_dma.raw";
01033 int8_t *circ_file = "/dev/circbuf";
01034
01035 int8_t *res_file;
01036 struct param p;
01037 pthread_t pid;
01038
01039 int _fd, c;
01040 for(c = 0; c < 20; c++)
01041 if(_fd = open("/dev/stream", O_RDONLY) < 0)
01042 usleep(50000);
01043 else
01044 break;
01045
01046 if(_fd < 0) {
01047 fprintf(stderr, "streamer already running, exit\n");
01048 return -1;
01049 }
01050
01051 p.dport = DEFAULT_DEST_PORT;
01052 p.ttl = DEFAULT_TTL;
01053 p.meth = MMAP_METHOD;
01054 p.dst = DEFAULT_DEST_IP;
01055 p.raw = 1;
01056 p.verbose = 0;
01057 p.web = 0;
01058 p.zero = 0;
01059 p.rtsp = 1;
01060 p.rtsp_port = DEFAULT_RTSP_PORT;
01061 p.rtsp_use_cmd_port = 0;
01062 p.rtsp_use_cmd_addr = 0;
01063 p.fps_soft = 0;
01064 p.rtsp_qt_compat = 0;
01065 p.fd_udp = 0;
01066 p.fd_raw = 0;
01067 p.hw_fps = 0;
01068 memset(&p.msg, 0, sizeof(struct msghdr));
01069
01070 opt_parse(argc, argv, &p);
01071
01072 if(p.hw_fps != 0)
01073 ioctl(_fd, _IO(IOC_STREAM_SET_FPS, 0x00), p.hw_fps);
01074 if(p.zero) {
01075 p.meth = READ_METHOD;
01076 if(p.web <= 0)
01077 p.web = DEFAULT_REFRESH_INTERVAL;
01078 p.rtsp = 0;
01079 }
01080 if(p.meth == MMAP_METHOD && p.web) {
01081 fprintf(stderr, "\nWARNING!!! Webcam mode can be activated only with READ method (option -r)\n\n");
01082 p.web = 0;
01083 }
01084 if(p.rtsp && p.rtsp_qt_compat && !p.rtsp_use_cmd_addr) {
01085 fprintf(stderr, "\nERROR!!! You MUST use --rtsp-use-opt-addr with --rtsp-qt-compat\n\n");
01086 usage(&p, 1);
01087 }
01088
01089 if(get_src_addr(&p) != 0) {
01090 return -1;
01091 }
01092 #ifdef NO_IOCTLS_IN_CIRCBUF
01094 if((ioctl_fd = open(ccam_file, O_RDWR)) < 0) {
01095 fprintf(stderr, "Can't open device %s\n",ccam_file);
01096 return -1;
01097 }
01098
01099 if(p.meth == READ_METHOD)
01100 fd=ioctl_fd ;
01101 else {
01102 if((fd = open(circ_file, O_RDWR)) < 0) {
01103 fprintf(stderr, "Can't open device %s\n",circ_file);
01104 return -1;
01105 }
01106 }
01107 #else
01108 if(p.meth == READ_METHOD)
01109 res_file = ccam_file;
01110 else
01111 res_file = circ_file;
01112 if((fd = open(res_file, O_RDWR)) < 0) {
01113 fprintf(stderr, "Cann't open device!\n");
01114 return -1;
01115 }
01116 ioctl_fd=fd;
01117 #endif
01118 if(p.meth == READ_METHOD) {
01119 wbuf = (int8_t *) malloc(MAX_JPEG_BUF);
01120 } else {
01121 start = (unsigned long *) valloc(0x100000);
01122 buf_size = lseek(fd, 0, 2);
01123 ccam_dma_buf = (unsigned long *) mmap(start + (TMP_BUF_OFFS >> 2), buf_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
01124 if((int) ccam_dma_buf == -1) {
01125 fprintf(stderr, "mmap error!\n");
01126 return -1;
01127 }
01128 }
01129
01130 if(p.rtsp) {
01131 fprintf(stderr, "\n\tRTSP server is listening on the port %d.\n", p.rtsp_port);
01132 if(!p.rtsp_use_cmd_addr) {
01133 fprintf(stderr, "\tDestination address will got from rtsp request.\n");
01134 }
01135 if(!p.rtsp_use_cmd_port) {
01136 fprintf(stderr, "\tDestination port will got from rtsp request.\n");
01137 }
01138 fprintf(stderr, "\n\tStream is accessible by uri rtsp://%s:%d\n\n", p.src, p.rtsp_port);
01139 }
01140
01141 str_stop = 0;
01142 str_teardown = 0;
01143 str_count = 0;
01144
01145 if(p.rtsp){
01146 str_setup = 0;
01147 str_play = 0;
01148 if(pthread_create(&pid, NULL, rtsp_loop, &p) != 0) {
01149 fprintf(stderr, "thread create error!\n");
01150 return -1;
01151 }
01152 } else {
01153 str_setup = 1;
01154 str_play = 1;
01155 }
01156
01157 if(p.rtsp_qt_compat) {
01158 str_setup = 1;
01159 str_play = 1;
01160 }
01161
01162 while(1) {
01163 if(!str_setup && !str_stop && !str_teardown) {
01164 sched_yield();
01165
01166 continue;
01167 }
01168
01169 if(str_setup) {
01170 str_setup = 0;
01171 }
01172
01173 if(str_teardown) {
01174 str_teardown = 0;
01175
01176 sched_yield();
01177 continue;
01178 }
01179 if(str_stop)
01180 break;
01181 res = grab_and_send(&p);
01182 str_play = 0;
01183 str_setup = 0;
01184 if(p.rtsp_qt_compat) {
01185 str_setup = 1;
01186 str_play = 1;
01187 }
01188 if(res != 0)
01189 return -1;
01190 if(str_stop)
01191 break;
01192 }
01193
01194 if(p.meth == MMAP_METHOD) {
01195 munmap(start + TMP_BUF_OFFS, buf_size);
01196 }
01197
01198 if(p.meth == READ_METHOD) {
01199 free(wbuf);
01200 }
01201
01202 return 0;
01203 }
01204
01205