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
00021
00022 #ifdef VIDEO_DEBUG
00023 #define D(a) a
00024 #else
00025 #define D(a)
00026 #endif
00027
00028
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
00098 f_quality = -1;
00099
00100
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
00124 v_t_sec = 0;
00125 v_t_usec = 0;
00126 v_frames = 0;
00127
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
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) {
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) {
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
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
00294
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
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
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
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
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
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
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
00447
00448 return 0;
00449 } else if(frame_len <0) {
00450 D( cerr << __FILE__<< ":"<< __FUNCTION__ << ":" <<__LINE__<< "capture returned negative" << frame_len << endl;)
00451
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);
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
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
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
00516 rtp_packets++;
00517 rtp_octets += packet_len + 8;
00518
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
00548
00549 return 1;
00550 }