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 #undef VIDEO_DEBUG
00020 //#define VIDEO_DEBUG
00021 
00022 #ifdef VIDEO_DEBUG
00023         #define D(a) a
00024 #else
00025         #define D(a)
00026 #endif
00027 
00028 //Video *video = NULL;
00029 
00030 #define QTABLES_INCLUDE
00031 
00032 int fd_stream =   0;
00033 int fd_circbuf =  0;
00034 int fd_jpeghead = 0; 
00035 int fd_fparmsall =   0;
00036 int lastDaemonBit= DAEMON_BIT_STREAMER;
00037 
00038 
00039 struct framepars_all_t   *frameParsAll;
00040 struct framepars_t       *framePars;
00041 unsigned long            *globalPars; 
00042 
00043 
00044 Video::Video(void) {
00045 D(cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << endl;)
00046         stream_name = "video";
00047         fd_fparmsall = open("/dev/frameparsall", O_RDWR);
00048         if(fd_fparmsall < 0)
00049            throw("can't open /dev/frameparsall");
00051         frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ, MAP_SHARED, fd_fparmsall, 0);
00052         if((int)frameParsAll == -1)
00053           throw("Error in mmap /dev/frameparsall");
00054         framePars=frameParsAll->framePars;
00055         globalPars=frameParsAll->globalPars;
00056         waitDaemonEnabled(-1); 
00057         for(int c = 0; c < 20; c++)
00058                 if((fd_stream = open("/dev/stream", O_RDWR)) < 0)
00059                         usleep(50000);
00060                 else
00061                         break;
00062         if(fd_stream < 0) throw("can't open /dev/stream");
00063         fd_circbuf = open("/dev/circbuf", O_RDONLY);
00064         if(fd_circbuf < 0)
00065                 throw("can't open /dev/circbuf");
00066         buffer_length = lseek(fd_circbuf, 0, SEEK_END);
00068         buffer_ptr = (unsigned long *)mmap(0, buffer_length, PROT_READ, MAP_SHARED, fd_circbuf, 0);
00069         if((int)buffer_ptr == -1)
00070            throw("Error in mmap /dev/circbuf");
00071         buffer_ptr_s = (unsigned long *)mmap(buffer_ptr + (buffer_length >>2 ), buffer_length, PROT_READ, MAP_FIXED | MAP_SHARED, fd_circbuf, 0);   
00072         if((int)buffer_ptr_s == -1)
00073            throw("Error in second mmap /dev/circbuf");
00076 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " frame=" <<GLOBALPARS(G_THIS_FRAME)<< " buffer_length=" << buffer_length <<endl;)
00077         while  (GLOBALPARS(G_THIS_FRAME) < 10) {
00078           lseek(fd_circbuf,LSEEK_CIRC_TOWP,SEEK_END); 
00079           lseek(fd_circbuf,LSEEK_CIRC_WAIT,SEEK_END); 
00080         }
00082         lseek(fd_circbuf,LSEEK_CIRC_WAIT,SEEK_END);
00083         lseek(fd_circbuf,LSEEK_CIRC_WAIT,SEEK_END);
00084 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " frame=" <<GLOBALPARS(G_THIS_FRAME)<< " buffer_length=" << buffer_length <<endl;)
00085         fd_jpeghead = open("/dev/jpeghead", O_RDWR);
00086         if(fd_jpeghead < 0)
00087            throw("can't open /dev/jpeghead");
00088         _fd = fd_stream;
00089         qtables_include = true;
00090 
00091         SSRC = 12;
00092         _ptype = 26;
00093         rtp_socket = NULL;
00094         rtcp_socket = NULL;
00095         _play = false;
00096         prev_jpeg_wp = 0;
00097 //      buffer_length = 0;
00098         f_quality = -1;
00099         
00100         // create thread...
00101         init_pthread((void *)this);
00102 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << endl;)
00103 
00104 }
00105 
00106 Video::~Video(void) {
00107         if(fd_circbuf > 0)
00108                 close(fd_circbuf);
00109         if(fd_stream > 0)
00110                 close(fd_stream);
00111         if(fd_jpeghead >0)
00112                 close (fd_jpeghead);
00113         if(fd_fparmsall >0)
00114                 close (fd_fparmsall);
00115 
00116 }
00118 #define TURN_COMPRESSOR_ON 0
00119 void Video::Start(string ip, long port) {
00120 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << "_play=" << _play << endl;)
00121 
00122         if(_play) return; 
00123         // statistic
00124         v_t_sec = 0;
00125         v_t_usec = 0;
00126         v_frames = 0;
00127         // create udp socket
00128         f_width = width();
00129         f_height = height();
00131 #if TURN_COMPRESSOR_ON
00132         unsigned long write_data[4];
00133         write_data[0]=FRAMEPARS_SETFRAME;
00134         write_data[1]=GLOBALPARS(G_THIS_FRAME)+1;
00135         write_data[2]=P_COMPRESSOR_RUN;
00136         write_data[3]=COMPRESSOR_RUN_CONT;
00137         write(fd_fparmsall, write_data, sizeof(write_data));
00138 #endif
00139         RTP_Stream::Start(ip, port);
00140 }
00141 
00142 void Video::Stop(void) {
00143         if(!_play)
00144                 return;
00145         RTP_Stream::Stop();
00146         _play=false;
00147         // destroy udp socket
00148         prev_jpeg_wp = 0;
00149 }
00150 
00151 
00158 unsigned long Video::getGPValue(unsigned long GPNumber) {
00159    return (GPNumber>=FRAMEPAR_GLOBALS)?
00160               GLOBALPARS(GPNumber):
00161               framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[GPNumber];
00162 }
00163 
00169 void Video::setGValue(unsigned long  GNumber,   unsigned long value) {
00170     GLOBALPARS(GNumber)=value;
00171 }
00172 
00179 bool  Video::waitDaemonEnabled(int daemonBit) { // <0 - use default
00180    if ((daemonBit>=0) && (daemonBit<32)) lastDaemonBit=daemonBit;
00181    unsigned long this_frame=this_frame=GLOBALPARS(G_THIS_FRAME);
00184   D(cerr << " lseek(fd_circbuf, LSEEK_DAEMON_CIRCBUF+lastDaemonBit, SEEK_END)... " << endl;)
00185    lseek(fd_circbuf, LSEEK_DAEMON_CIRCBUF+lastDaemonBit, SEEK_END); 
00186   D(cerr << "...done" << endl;)
00187    
00188    if (this_frame==GLOBALPARS(G_THIS_FRAME)) return true;
00189    return false;
00190 }
00191 
00197 bool  Video::isDaemonEnabled(int daemonBit) { // <0 - use default
00198    if ((daemonBit>=0) && (daemonBit<32)) lastDaemonBit=daemonBit;
00199    return ((framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[P_DAEMON_EN] & (1 <<lastDaemonBit))!=0);
00200 }
00201 
00202 
00211 long Video::getFramePars(struct interframe_params_t * frame_pars, long before) {
00212    long cur_pointer,p;
00213    long this_pointer=lseek(fd_circbuf,0,SEEK_CUR); 
00214    char * char_buffer_ptr = (char *) buffer_ptr;
00215    if (lseek(fd_circbuf,LSEEK_CIRC_VALID,SEEK_END) < 0 ) { 
00216      this_pointer=lseek(fd_circbuf,LSEEK_CIRC_LAST,SEEK_END);    
00217    }
00218    cur_pointer=this_pointer;
00219    if (!before) lseek(fd_circbuf,LSEEK_CIRC_WAIT,SEEK_END);
00220    while (before && (((p=lseek(fd_circbuf,LSEEK_CIRC_PREV,SEEK_END)))>=0)) { 
00221      cur_pointer=p;
00222      before--;
00223    }
00225    while (before>0) {
00226      lseek(fd_circbuf, this_pointer, SEEK_SET);
00227      lseek(fd_circbuf,LSEEK_CIRC_WAIT,SEEK_END);
00228      this_pointer=lseek(fd_circbuf,LSEEK_CIRC_NEXT,SEEK_END);
00229      before--;
00230    }
00231    long metadata_start=cur_pointer-32;
00232    if (metadata_start<0) metadata_start+=buffer_length;
00234 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " before=" << before << " metadata_start=" << metadata_start << endl;)
00235 
00236    memcpy (frame_pars, &char_buffer_ptr[metadata_start],32);
00237    long jpeg_len=frame_pars->frame_length; 
00238    if (frame_pars->signffff !=0xffff) {
00239      cerr << "Wrong signature in getFramePars() (broken frame)\n" << endl;
00240      return -1;
00241    }
00244    long timestamp_start=(cur_pointer)+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; 
00245    if (timestamp_start >= buffer_length) timestamp_start-= buffer_length;
00246    memcpy (&(frame_pars->timestamp_sec), &char_buffer_ptr[timestamp_start],8);
00247    lseek(fd_circbuf, this_pointer, SEEK_SET); 
00248 //D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " this_pointer=" << this_pointer << " cur_pointer=" << cur_pointer << endl;)
00249    return cur_pointer;
00250 
00251 }
00252 
00253 
00256 #define FRAMEPARS_BEFORE 0 
00257 int Video::width(void) {
00258     struct interframe_params_t frame_pars;
00259     if (getFramePars(&frame_pars, FRAMEPARS_BEFORE) < 0) return -1; 
00260 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " frame_pars.width=" << frame_pars.width << endl;)
00261     used_width=frame_pars.width;
00262     return frame_pars.width;
00263 }
00264 
00265 int Video::height(void) {
00266     struct interframe_params_t frame_pars;
00267     if (getFramePars(&frame_pars, FRAMEPARS_BEFORE) < 0) return -1; 
00268 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " frame_pars.height=" << frame_pars.height << endl;)
00269     used_height=frame_pars.height;
00270     return frame_pars.height;
00271 }
00272 
00273 int Video::quality(void) {
00274     struct interframe_params_t frame_pars;
00275     if (getFramePars(&frame_pars, FRAMEPARS_BEFORE) < 0) return -1; 
00276 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " frame_pars.quality2=" << frame_pars.quality2 << endl;)
00277     return frame_pars.quality2;
00278 }
00279 
00280 float Video::fps(void) {
00281     struct interframe_params_t frame_pars,prev_pars;
00282     if ((getFramePars(&frame_pars, FRAMEPARS_BEFORE) < 0) ||
00283         (getFramePars(&prev_pars,  FRAMEPARS_BEFORE+1) < 0))  return -1; 
00284 
00285 
00286 
00287     float fps = ((frame_pars.timestamp_sec-prev_pars.timestamp_sec)*1000000)+frame_pars.timestamp_usec-prev_pars.timestamp_usec;
00288     fps=1000000/fps;
00289 D(cerr  << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__ << " fps=" << fps << endl;)
00290     used_fps=fps;
00291     return fps;
00292 }
00293 //#define FRAMES_AHEAD_FPS 3 /// number of frames ahead of current to frite FPS limit
00294 //#define FRAMES_SKIP_FPS  3 /// number of frames to wait after target so circbuf will have at least 2 frames with new fps for calculation
00295 void Video::fps(float fps) {
00296     if(fps < 0.01) return;
00298 
00299     unsigned long write_data[6];
00300     long target_frame=GLOBALPARS(G_THIS_FRAME)+FRAMES_AHEAD_FPS;
00301     write_data[0]=FRAMEPARS_SETFRAME;
00302     write_data[1]=target_frame; 
00303     write_data[2]=P_FP1000SLIM;
00304     write_data[3]=(unsigned long) fps*1000;
00305     write_data[4]=P_FPSFLAGS;
00306     write_data[5]=3;
00307     long rslt=write(fd_fparmsall, write_data, sizeof(write_data));
00308     if (rslt==sizeof(write_data)) { 
00309       lseek(fd_fparmsall,LSEEK_FRAME_WAIT_ABS+target_frame+FRAMES_SKIP_FPS, SEEK_END); 
00310     }
00311 }
00312 #define USE_REAL_OLD_TIMESTAMP 0
00313 long Video::capture(void) {
00314         long frame_len;
00315 struct interframe_params_t frame_pars;
00316 //      long len;
00317 
00318         int quality;
00319         unsigned long latestAvailableFrame_ptr;
00320         unsigned long frameStartByteIndex;
00321         int before;
00323         if ((framePars[GLOBALPARS(G_THIS_FRAME) & PARS_FRAMES_MASK].pars[P_DAEMON_EN] & (1 <<lastDaemonBit))==0) {
00324             return -DAEMON_DISABLED;  
00325         }
00326         frameStartByteIndex = lseek(fd_circbuf, LSEEK_CIRC_TOWP, SEEK_END);  
00327         latestAvailableFrame_ptr=frameStartByteIndex;
00328         lseek(fd_circbuf, LSEEK_CIRC_WAIT, SEEK_END);
00329 
00330         frame_ptr = (char *)((unsigned long)buffer_ptr + latestAvailableFrame_ptr);
00331         if(latestAvailableFrame_ptr < 32)
00332                 latestAvailableFrame_ptr += buffer_length;
00333         latestAvailableFrame_ptr >>= 2;
00334         frame_len = buffer_ptr[latestAvailableFrame_ptr - 1];
00335         // read timestamp
00336         char *ts_ptr = (char *)((unsigned long)frame_ptr + (long)(((frame_len + CCAM_MMAP_META + 3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC));
00337         unsigned long t[2];
00338         memcpy(&t, (void *)ts_ptr, 8);
00339         f_tv.tv_sec = t[0];
00340         f_tv.tv_usec = t[1];
00341         // read Q value
00342         char *meta = (char *)frame_ptr;
00343         meta -= 32;
00344         if(meta < (char *)buffer_ptr) meta += buffer_length;
00345         struct interframe_params_t *fp = (struct interframe_params_t *)meta;
00350         if ((fp->width!=used_width) || (fp->height!=used_height)) {
00351            for (before=1; before <= (int) getGPValue(G_SKIP_DIFF_FRAME);before++) {
00352                if (((frameStartByteIndex=getFramePars(&frame_pars, before))) &&
00353                   (frame_pars.width==used_width) && (frame_pars.height==used_height)) {
00356                   latestAvailableFrame_ptr=frameStartByteIndex;
00357                   frame_ptr = (char *)((unsigned long)buffer_ptr + latestAvailableFrame_ptr);
00358                   if(latestAvailableFrame_ptr < 32)
00359                   latestAvailableFrame_ptr += buffer_length;
00360                   latestAvailableFrame_ptr >>= 2;
00361                   frame_len = buffer_ptr[latestAvailableFrame_ptr - 1];
00362 #if USE_REAL_OLD_TIMESTAMP
00364                   ts_ptr = (char *)((unsigned long)frame_ptr + (long)(((frame_len + CCAM_MMAP_META + 3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC));
00365                   memcpy(&t, (void *)ts_ptr, 8);
00366                   f_tv.tv_sec = t[0];
00367                   f_tv.tv_usec = t[1];
00368 #endif
00370                   char *meta = (char *)frame_ptr;
00371                   meta -= 32;
00372                   if(meta < (char *)buffer_ptr) meta += buffer_length;
00373                   fp = (struct interframe_params_t *)meta;
00374                   break;
00375                }
00376            }
00377            if (before > (int) getGPValue(G_SKIP_DIFF_FRAME)) {
00378 D(      cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< " Killing stream because of frame size change " << endl;)
00379              return -SIZE_CHANGE; 
00380            }
00381 D(      cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< " Waiting for the original frame size to be restored , using " << before << " frames ago" << endl;)
00382         }
00385         quality = fp->quality2;
00386         if(qtables_include && quality != f_quality) {
00387 D(      cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< " Updating quality tables, new quality is " << quality << endl;)
00388           lseek(fd_jpeghead, frameStartByteIndex | 2, SEEK_END); 
00389           read (fd_jpeghead, (void *)&qtable[0], 128);
00390         }
00391         f_quality = quality;
00392         // check statistic
00393         if(Streamer::instance()->opt_present("d")) {
00394                 if(v_t_sec == 0) {
00395                         v_frames = 0;
00396                         v_t_sec = f_tv.tv_sec;
00397                         v_t_usec = f_tv.tv_usec;
00398                 }
00399                 long t = f_tv.tv_sec - v_t_sec;
00400                 t *= 1000000;
00401                 t += f_tv.tv_usec;
00402                 t -= v_t_usec;
00403                 if(t >= 1000000) {
00404                         float fps = v_frames * 1000000;
00405                         fps /= t;
00406                         char buf[128];
00407                         float Tframe = 1.0 / fps;
00408                         Tframe *= 96000000.0;
00409 //                      Tframe *= 48000000.0;
00410                         sprintf(buf, "fps == %3.6f, frames == %d, time == %d; Tframe == %.1f clk, ts: %d:%d",
00411                                       fps, v_frames, (int) t, Tframe, (int)f_tv.tv_sec, (int)f_tv.tv_usec);
00412                         cerr << buf; 
00413                         v_t_sec = 0;
00414                         unsigned long t[4];
00415                         ioctl(fd_stream, _IO(IOC_STREAM_GET_TIME, 0x00), (void *)&t[0]);
00416                         sprintf(buf, "; sys time == %ld:%06ld; FPGA time == %ld:%06ld", t[0], t[1], t[2], t[3]);
00417                         cerr << buf << endl;
00418                         long long ts, tf, d;
00419                         ts = t[0];
00420                         ts <<= 32;
00421                         ts += t[1];
00422                         tf = t[2];
00423                         tf <<= 32;
00424                         tf += t[3];
00425                         if(ts > tf)
00426                                 d = ts - tf;
00427                         else
00428                                 d = tf - ts;
00429                         unsigned long t_usec = d & 0xFFFFFFFF;
00430                         d >>= 32;
00431                         unsigned long t_sec = d & 0xFFFFFFFF;
00432                         cerr << "delta time: " << t_sec << ":" << t_usec << endl;
00433                 }
00434                 v_frames++;
00435         }
00436         return frame_len;       
00437 }
00438 
00439 long Video::process(void) {
00440 //D(        cerr << "< ";)
00441         int _plen = 1400;
00442         int to_send = _plen;
00443         int _qtables_len = 128 + 4;
00444         long frame_len = capture();
00445         if(frame_len == 0) {
00446 //D(           cerr << "[";)
00447 //              return false;
00448                 return 0; 
00449         } else  if(frame_len <0) {
00450 D(      cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< "capture returned negative" << frame_len << endl;)
00451 //              return false;
00452                 return frame_len; 
00453         }
00454 
00455         int to_send_len = frame_len;
00456         unsigned char h[20 + 4];
00457         int packet_len = 0;
00458         unsigned char *data = (unsigned char *)frame_ptr;
00459 
00460         float f = f_tv.tv_usec;
00461         f /= 1000000;
00462         f += (f_tv.tv_sec & 0x7FFF); // use a mask to cut an odd part of seconds to prevent overflow of "float" type
00463         f *= 90000;
00464         timestamp = (unsigned long)f;
00465         unsigned long ts = htonl(timestamp);
00466 
00467         long offset = 0;
00468         void *v_ptr[4];
00469         int v_len[4] = {0, 0, 0, 0};
00470         bool first = true;
00471         while(to_send_len && _play) {
00472                 unsigned long pnum = htons(packet_num);
00473                 bool last = false;
00474                 to_send = _plen;
00475                 if(qtables_include && first)
00476                         to_send = _plen - _qtables_len;
00477                 if(to_send_len <= to_send) {
00478                         packet_len = to_send_len;
00479                         to_send_len = 0;
00480                         last = true;
00481                 } else {
00482                         packet_len = to_send;
00483                         to_send_len -= to_send;
00484                 }
00485                 // make RTP packet
00486                 h[0] = 0x80;
00487                 if(!last)
00488                         h[1] = _ptype;
00489                 else
00490                         h[1] = 0x80 + _ptype;
00491                 memcpy((void *)&h[2], (void *)&pnum, 2);
00492                 memcpy((void *)&h[4], (void *)&ts, 4);
00493                 memcpy((void *)&h[8], (void *)&SSRC, 4);
00494                 // make MJPEG header
00495                 unsigned long off = htonl(offset);
00496                 memcpy((void *)&h[12], (void *)&off, 4);
00497                 h[12] = 0x00;
00498                 h[16] = 0x01;
00499                 unsigned int q = f_quality;
00500                 if(qtables_include)
00501                         q += 128;
00502                 h[17] = (unsigned char)(q & 0xFF);
00503                 if(f_width <= 2040)
00504                         h[18] = (f_width / 8) & 0xFF;
00505                 else
00506                         h[18] = 0;
00507                 if(f_height <= 2040)
00508                         h[19] = (f_height / 8) & 0xFF;
00509                 else
00510                         h[19] = 0;
00511                 h[20] = 0;
00512                 h[21] = 0;
00513                 unsigned short l = htons(128);
00514                 memcpy((void *)&h[22], (void *)&l, 2);
00515                 // update RTCP statistic
00516                 rtp_packets++;
00517                 rtp_octets += packet_len + 8; // data + MJPEG header
00518                 // send vector
00519                 if(first) {
00520                         v_ptr[0] = h;
00521                         if(qtables_include) {
00522                                 v_len[0] = 24;
00523                                 v_ptr[1] = qtable;
00524                                 v_len[1] = 128;
00525                                 v_ptr[2] = data;
00526                                 v_len[2] = packet_len;
00527                                 rtp_socket->send3v(&v_ptr[0], &v_len[0]);
00528                         } else {
00529                                 v_len[0] = 20;
00530                                 v_ptr[1] = data;
00531                                 v_len[1] = packet_len;
00532                                 rtp_socket->send2v(&v_ptr[0], &v_len[0]);
00533                         }
00534                         first = false;
00535                 } else {
00536                         v_ptr[0] = h;
00537                         v_len[0] = 20;
00538                         v_ptr[1] = data;
00539                         v_len[1] = packet_len;
00540                         rtp_socket->send2v(&v_ptr[0], &v_len[0]);
00541                 }
00542                 // --==--
00543                 packet_num++;
00544                 data += packet_len;
00545                 offset += packet_len;
00546         }
00547 //D(        cerr << "]";)
00548 //      return true;
00549         return 1;
00550 }

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1