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