apps/astreamer/video.cpp

Go to the documentation of this file.
00001 #include "video.h"
00002 
00003 #include <sys/types.h>
00004 #include <sys/stat.h>
00005 #include <sys/ioctl.h>
00006 #include <sys/mman.h>
00007 #include <arpa/inet.h>
00008 #include <fcntl.h>
00009 #include <unistd.h>
00010 
00011 #include <asm/elphel/c313a.h>
00012 #include <asm/elphel/hist.h>
00013 #include <asm/elphel/ext353.h>
00014 
00015 #include <iostream>
00016 #include "streamer.h"
00017 using namespace std;
00018 
00019 //Video *video = NULL;
00020 
00021 #define QTABLES_INCLUDE
00022 
00023 int fd_stream = 0;
00024 int fd_circbuf = 0;
00025 
00026 Video::Video(void) {
00027         stream_name = "video";
00028         for(int c = 0; c < 20; c++)
00029                 if((fd_stream = open("/dev/stream", O_RDWR)) < 0)
00030                         usleep(50000);
00031                 else
00032                         break;
00033         if(fd_stream < 0)
00034                 throw("can't open /dev/stream");
00035         fd_circbuf = open("/dev/circbuf", O_RDONLY);
00036         if(fd_circbuf < 0)
00037                 throw("can't open /dev/circbuf");
00038 //      fd_ctl = open();
00039         fd_ctl = fd_circbuf;
00040 //      fd_ctl = open("/dev/circbuf", O_RDWR);
00041 //      if(fd_ctl < 0)
00042 //              throw("can't open /dev/circbuf");
00044         fd_ioctl = open("/dev/sensorpars", O_RDWR);
00045         if(fd_ioctl < 0)
00046                 throw("can't open /dev/sensorpars");
00047 
00048         _fd = fd_stream;
00049 
00050         qtables_include = true;
00051 
00052         SSRC = 12;
00053         _ptype = 26;
00054         rtp_socket = NULL;
00055         rtcp_socket = NULL;
00056         _play = false;
00057         prev_jpeg_wp = 0;
00058         buffer_length = 0;
00059         f_quality = -1;
00060         
00061         // create thread...
00062         init_pthread((void *)this);
00063 }
00064 
00065 Video::~Video(void) {
00066         if(fd_ioctl > 0)
00067                 close(fd_ioctl);
00068         if(fd_circbuf > 0)
00069                 close(fd_circbuf);
00070         if(fd_stream > 0)
00071                 close(fd_stream);
00072 }
00073 
00074 void Video::Start(string ip, long port) {
00075         if(_play)
00076                 return;
00077         // statistic
00078         v_t_sec = 0;
00079         v_t_usec = 0;
00080         v_frames = 0;
00081         // ----
00082         if(buffer_length == 0)
00083                 buffer_length = lseek(fd_ctl, 0, 2);
00084         buffer_ptr = (unsigned long *)mmap(0, buffer_length, PROT_READ, MAP_SHARED, fd_circbuf, 0);
00085         buffer_ptr_s = (unsigned long *)mmap(buffer_ptr + (buffer_length / 4), buffer_length, PROT_READ, MAP_FIXED | MAP_SHARED, fd_circbuf, 0);
00086 //char b[256];
00087 //sprintf(b, "0x%08X, 0x%08X", buffer_ptr, buffer_ptr_s);
00088 //cerr << b << endl;
00089         // create udp socket
00090         f_width = width();
00091         f_height = height();
00092         // start compressor...
00093         int status = ioctl(fd_ioctl, _IO(CMOSCAM_IOCTYPE, IO_CCAM_MONITOR_SEQ), 0);
00094 //      if(status == CAMSEQ_RUN || status == CAMSEQ_SINGLE)
00095 //              ioctl(fd_ioctl, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_STOP);
00096         if(status != CAMSEQ_RUN)
00097                 ioctl(fd_ioctl, _IO(CMOSCAM_IOCTYPE, IO_CCAM_JPEG), JPEG_CMD_START);
00098         RTP_Stream::Start(ip, port);
00099 }
00100 
00101 void Video::Stop(void) {
00102         if(!_play)
00103                 return;
00104         RTP_Stream::Stop();
00105         // destroy udp socket
00106         prev_jpeg_wp = 0;
00107         munmap(buffer_ptr_s, buffer_length);
00108         munmap(buffer_ptr, buffer_length);
00109 }
00110 
00111 int Video::width(void) {
00112         return ioctl(fd_ioctl, _CCCMD(CCAM_RPARS, P_ACTUAL_WIDTH), 0);
00113 }
00114 
00115 int Video::height(void) {
00116         return ioctl(fd_ioctl, _CCCMD(CCAM_RPARS, P_ACTUAL_HEIGHT), 0);
00117 }
00118 
00119 int Video::quality(void) {
00120         return ioctl(fd_ioctl, _CCCMD(CCAM_RPARS, P_QUALITY), 0);
00121 }
00122 
00123 float Video::fps(void) {
00124         float fps = ioctl(fd_ioctl, _CCCMD(CCAM_RPARS, P_FP100S), 0);
00125         fps *= 0.01;
00126         return fps;
00127 }
00128 
00129 void Video::fps(float fps) {
00130         if(fps > 0.01)
00131                 ioctl(fd_stream, _IO(IOC_STREAM_SET_FPS, 0x00), int(fps * 100.0));
00132 }
00133 
00134 long Video::capture(void) {
00135         long frame_len;
00136         long len;
00137 
00138         int quality;
00139         unsigned long last_ptr;
00140         last_ptr = lseek(fd_circbuf, CIRCLSEEK_TOWP, SEEK_END);
00141         lseek(fd_circbuf, CIRCLSEEK_WAIT, SEEK_END);
00142         frame_ptr = (char *)((unsigned long)buffer_ptr + last_ptr);
00143         if(last_ptr < 32)
00144                 last_ptr += buffer_length;
00145         last_ptr >>= 2;
00146         frame_len = buffer_ptr[last_ptr - 1];
00147         // read timestamp
00148         char *ts_ptr = (char *)((unsigned long)frame_ptr + (long)(((frame_len + CCAM_MMAP_META + 3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC));
00149         unsigned long t[2];
00150         memcpy(&t, (void *)ts_ptr, 8);
00151         f_tv.tv_sec = t[0];
00152         f_tv.tv_usec = t[1];
00153         // read Q value
00154         char *meta = (char *)frame_ptr;
00155         meta -= 32;
00156         if(meta < (char *)buffer_ptr)
00157                 meta += buffer_length;
00158         struct frame_params_t *fp = (struct frame_params_t *)meta;
00159         quality = fp->quality;
00160         if(qtables_include && quality != f_quality) {
00161                 ioctl(fd_stream, _IO(IOC_STREAM_GET_QTABLES, (unsigned char)quality), (void *)&qtable[0]);
00162 //cerr << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> update tables..." << endl;
00163         }
00164         f_quality = quality;
00165         // check statistic
00166         if(Streamer::instance()->opt_present("d")) {
00167                 if(v_t_sec == 0) {
00168                         v_frames = 0;
00169                         v_t_sec = f_tv.tv_sec;
00170                         v_t_usec = f_tv.tv_usec;
00171                 }
00172                 long t = f_tv.tv_sec - v_t_sec;
00173                 t *= 1000000;
00174                 t += f_tv.tv_usec;
00175                 t -= v_t_usec;
00176                 if(t >= 1000000) {
00177                         float fps = v_frames * 1000000;
00178                         fps /= t;
00179                         char buf[128];
00180                         float Tframe = 1.0 / fps;
00181                         Tframe *= 96000000.0;
00182 //                      Tframe *= 48000000.0;
00183                         sprintf(buf, "fps == %3.6f, frames == %d, time == %d; Tframe == %.1f clk, ts: %d:%d", fps, v_frames, (int) t, Tframe, f_tv.tv_sec, f_tv.tv_usec);
00184                         cerr << buf; 
00185                         v_t_sec = 0;
00186                         unsigned long t[4];
00187                         ioctl(fd_stream, _IO(IOC_STREAM_GET_TIME, 0x00), (void *)&t[0]);
00188                         sprintf(buf, "; sys time == %d:%06d; FPGA time == %d:%06d", t[0], t[1], t[2], t[3]);
00189                         cerr << buf << endl;
00190                         long long ts, tf, d;
00191                         ts = t[0];
00192                         ts <<= 32;
00193                         ts += t[1];
00194                         tf = t[2];
00195                         tf <<= 32;
00196                         tf += t[3];
00197                         if(ts > tf)
00198                                 d = ts - tf;
00199                         else
00200                                 d = tf - ts;
00201                         unsigned long t_usec = d & 0xFFFFFFFF;
00202                         d >>= 32;
00203                         unsigned long t_sec = d & 0xFFFFFFFF;
00204                         cerr << "delta time: " << t_sec << ":" << t_usec << endl;
00205                 }
00206                 v_frames++;
00207         }
00208         return frame_len;       
00209 }
00210 
00211 bool Video::process(void) {
00212         int _plen = 1400;
00213         int to_send = _plen;
00214         int _qtables_len = 128 + 4;
00215         long frame_len = capture();
00216         if(frame_len <= 0)
00217                 return false;
00218 
00219         int to_send_len = frame_len;
00220         unsigned char h[20 + 4];
00221         int packet_len = 0;
00222         unsigned char *data = (unsigned char *)frame_ptr;
00223 
00224         float f = f_tv.tv_usec;
00225         f /= 1000000;
00226         f += (f_tv.tv_sec & 0x7FFF); // use a mask to cut an odd part of seconds to prevent overflow of "float" type
00227         f *= 90000;
00228         timestamp = (unsigned long)f;
00229         unsigned long ts = htonl(timestamp);
00230 
00231         long offset = 0;
00232         void *v_ptr[4];
00233         int v_len[4] = {0, 0, 0, 0};
00234         bool first = true;
00235         while(to_send_len && _play) {
00236                 unsigned long pnum = htons(packet_num);
00237                 bool last = false;
00238                 to_send = _plen;
00239                 if(qtables_include && first)
00240                         to_send = _plen - _qtables_len;
00241                 if(to_send_len <= to_send) {
00242                         packet_len = to_send_len;
00243                         to_send_len = 0;
00244                         last = true;
00245                 } else {
00246                         packet_len = to_send;
00247                         to_send_len -= to_send;
00248                 }
00249                 // make RTP packet
00250                 h[0] = 0x80;
00251                 if(!last)
00252                         h[1] = _ptype;
00253                 else
00254                         h[1] = 0x80 + _ptype;
00255                 memcpy((void *)&h[2], (void *)&pnum, 2);
00256                 memcpy((void *)&h[4], (void *)&ts, 4);
00257                 memcpy((void *)&h[8], (void *)&SSRC, 4);
00258                 // make MJPEG header
00259                 unsigned long off = htonl(offset);
00260                 memcpy((void *)&h[12], (void *)&off, 4);
00261                 h[12] = 0x00;
00262                 h[16] = 0x01;
00263                 unsigned int q = f_quality;
00264                 if(qtables_include)
00265                         q += 128;
00266                 h[17] = (unsigned char)(q & 0xFF);
00267                 if(f_width <= 2040)
00268                         h[18] = (f_width / 8) & 0xFF;
00269                 else
00270                         h[18] = 0;
00271                 if(f_height <= 2040)
00272                         h[19] = (f_height / 8) & 0xFF;
00273                 else
00274                         h[19] = 0;
00275                 h[20] = 0;
00276                 h[21] = 0;
00277                 unsigned short l = htons(128);
00278                 memcpy((void *)&h[22], (void *)&l, 2);
00279                 // update RTCP statistic
00280                 rtp_packets++;
00281                 rtp_octets += packet_len + 8; // data + MJPEG header
00282                 // send vector
00283                 if(first) {
00284                         v_ptr[0] = h;
00285                         if(qtables_include) {
00286                                 v_len[0] = 24;
00287                                 v_ptr[1] = qtable;
00288                                 v_len[1] = 128;
00289                                 v_ptr[2] = data;
00290                                 v_len[2] = packet_len;
00291                                 rtp_socket->send3v(&v_ptr[0], &v_len[0]);
00292                         } else {
00293                                 v_len[0] = 20;
00294                                 v_ptr[1] = data;
00295                                 v_len[1] = packet_len;
00296                                 rtp_socket->send2v(&v_ptr[0], &v_len[0]);
00297                         }
00298                         first = false;
00299                 } else {
00300                         v_ptr[0] = h;
00301                         v_len[0] = 20;
00302                         v_ptr[1] = data;
00303                         v_len[1] = packet_len;
00304                         rtp_socket->send2v(&v_ptr[0], &v_len[0]);
00305                 }
00306                 // --==--
00307                 packet_num++;
00308                 data += packet_len;
00309                 offset += packet_len;
00310         }
00311         return true;
00312 }

Generated on Thu Aug 7 16:18:58 2008 for elphel by  doxygen 1.5.1