00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <assert.h>
00018
00019 #include "video.h"
00020 #include "iaxclient_lib.h"
00021 #include "videoLib/video_grab.h"
00022 #include "iax-client.h"
00023 #ifdef USE_FFMPEG
00024 #include "codec_ffmpeg.h"
00025 #endif
00026 #ifdef USE_THEORA
00027 #include "codec_theora.h"
00028 #endif
00029
00030 #define VIDEO_BUFSIZ (1<<19)
00031
00032 extern int selected_call;
00033 extern struct iaxc_call * calls;
00034
00035 static int iaxc_video_width = 320;
00036 static int iaxc_video_height = 240;
00037 static int iaxc_video_framerate = 10;
00038 static int iaxc_video_bitrate = 150000;
00039 static int iaxc_video_fragsize = 1500;
00040 static int iaxc_video_format_preferred = 0;
00041 static int iaxc_video_format_allowed = 0;
00042 static struct iaxc_video_driver video_driver;
00043
00044
00045
00046
00047 static int iaxc_video_prefs = IAXC_VIDEO_PREF_RECV_LOCAL_RAW |
00048 IAXC_VIDEO_PREF_RECV_REMOTE_RAW;
00049
00050 #if 0
00051
00052 static int check_ccir_yuv(char *data) {
00053 int i;
00054 unsigned char pix;
00055 int err = 0;
00056
00057 for(i=0;i<iaxc_video_width * iaxc_video_height; i++) {
00058 pix = *data++;
00059 if( (pix < 16) || pix > 235) {
00060 fprintf(stderr, "check_ccir_yuv: Y pixel[%d] out of range: %d\n", i, pix);
00061 err++;
00062 }
00063 }
00064 for(i=0;i< iaxc_video_width * iaxc_video_height / 2; i++) {
00065 pix = *data++;
00066 if( (pix < 16) || pix > 239) {
00067 fprintf(stderr, "check_ccir_yuv: U/V pixel[%d] out of range: %d\n", i, pix);
00068 err++;
00069 }
00070 }
00071 return err;
00072 }
00073 #endif
00074
00075 EXPORT unsigned int iaxc_get_video_prefs(void)
00076 {
00077 return iaxc_video_prefs;
00078 }
00079
00080 EXPORT int iaxc_set_video_prefs(unsigned int prefs)
00081 {
00082 const unsigned int prefs_mask =
00083 IAXC_VIDEO_PREF_RECV_LOCAL_RAW |
00084 IAXC_VIDEO_PREF_RECV_LOCAL_ENCODED |
00085 IAXC_VIDEO_PREF_RECV_REMOTE_RAW |
00086 IAXC_VIDEO_PREF_RECV_REMOTE_ENCODED |
00087 IAXC_VIDEO_PREF_SEND_DISABLE |
00088 IAXC_VIDEO_PREF_RECV_RGB32 |
00089 IAXC_VIDEO_PREF_CAPTURE_DISABLE;
00090
00091 if ( prefs & ~prefs_mask )
00092 return -1;
00093
00094
00095
00096
00097
00098 if ( prefs & IAXC_VIDEO_PREF_CAPTURE_DISABLE ||
00099 ((prefs & IAXC_VIDEO_PREF_SEND_DISABLE) &&
00100 !(prefs & IAXC_VIDEO_PREF_RECV_LOCAL_RAW) &&
00101 !(prefs & IAXC_VIDEO_PREF_RECV_LOCAL_ENCODED)) )
00102 {
00103
00104
00105
00106 if (video_driver.stop)
00107 video_driver.stop(&video_driver);
00108 }
00109 else
00110 {
00111 if ( video_driver.start )
00112 {
00113 video_driver.start(&video_driver);
00114
00115
00116 if ( !video_driver.is_camera_working(&video_driver) )
00117 return -1;
00118 }
00119 }
00120
00121 iaxc_video_prefs = prefs;
00122
00123 return 0;
00124 }
00125
00126 EXPORT void iaxc_video_format_set_cap(int preferred, int allowed)
00127 {
00128 iaxc_video_format_preferred = preferred;
00129 iaxc_video_format_allowed = allowed;
00130 }
00131
00132 EXPORT void iaxc_video_format_get_cap(int *preferred, int *allowed)
00133 {
00134 *preferred = iaxc_video_format_preferred;
00135 *allowed = iaxc_video_format_allowed;
00136 }
00137
00138 EXPORT void iaxc_video_format_set(int preferred, int allowed, int framerate,
00139 int bitrate, int width, int height, int fs)
00140 {
00141 int real_pref = 0;
00142 int real_allowed = 0;
00143 #ifdef USE_FFMPEG
00144 int tmp_allowed;
00145 int i;
00146 #endif
00147
00148
00149 if ( width < IAXC_VIDEO_MIN_WIDTH )
00150 width = IAXC_VIDEO_MIN_WIDTH;
00151 else if ( width > IAXC_VIDEO_MAX_WIDTH )
00152 width = IAXC_VIDEO_MAX_WIDTH;
00153
00154 if ( height < IAXC_VIDEO_MIN_HEIGHT )
00155 height = IAXC_VIDEO_MIN_HEIGHT;
00156 else if ( height > IAXC_VIDEO_MAX_HEIGHT )
00157 height = IAXC_VIDEO_MAX_HEIGHT;
00158
00159 iaxc_video_framerate = framerate;
00160 iaxc_video_bitrate = bitrate;
00161 iaxc_video_width = width;
00162 iaxc_video_height = height;
00163 iaxc_video_fragsize = fs;
00164
00165 iaxc_video_format_allowed = 0;
00166 iaxc_video_format_preferred = 0;
00167
00168 if ( preferred && (preferred & ~IAXC_VIDEO_FORMAT_MASK) )
00169 {
00170 fprintf(stderr, "ERROR: Preferred video format invalid.\n");
00171 preferred = 0;
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 if ( preferred & IAXC_FORMAT_THEORA )
00183 real_pref = IAXC_FORMAT_THEORA;
00184
00185 #ifdef USE_FFMPEG
00186 if ( codec_video_ffmpeg_check_codec(preferred) )
00187 real_pref = preferred;
00188 #endif
00189
00190 if ( !real_pref )
00191 {
00192
00193
00194 fprintf(stderr, "Preferred codec (0x%08x) is not available. Switching to default", preferred);
00195 real_pref = IAXC_FORMAT_THEORA;
00196 }
00197
00198
00199
00200 if ( allowed & IAXC_FORMAT_THEORA )
00201 real_allowed |= IAXC_FORMAT_THEORA;
00202
00203 #ifdef USE_FFMPEG
00204
00205
00206
00207
00208
00209
00210 for ( i = 0; i <= 24; i++)
00211 {
00212 tmp_allowed = 1 << i;
00213 if ( (allowed & tmp_allowed) &&
00214 codec_video_ffmpeg_check_codec(tmp_allowed) )
00215 real_allowed |= tmp_allowed;
00216 }
00217 #endif
00218
00219 if ( !real_pref )
00220 {
00221 fprintf(stderr, "Audio-only client!\n");
00222 } else
00223 {
00224 iaxc_video_format_preferred = real_pref;
00225
00226
00227
00228
00229
00230
00231
00232 if ( real_allowed )
00233 {
00234 iaxc_video_format_allowed = real_allowed;
00235 } else
00236 {
00237 #ifdef USE_FFMPEG
00238 iaxc_video_format_allowed |= IAXC_FORMAT_H263_PLUS
00239 | IAXC_FORMAT_H263
00240 | IAXC_FORMAT_MPEG4
00241 | IAXC_FORMAT_H264;
00242 #endif
00243 iaxc_video_format_allowed |= IAXC_FORMAT_THEORA;
00244 }
00245 }
00246 }
00247
00248 void iaxc_video_params_change(int framerate, int bitrate, int width,
00249 int height, int fs)
00250 {
00251 struct iaxc_call *call;
00252
00253
00254 if ( framerate > 0 )
00255 iaxc_video_framerate = framerate;
00256 if ( bitrate > 0 )
00257 iaxc_video_bitrate = bitrate;
00258 if ( width > 0 )
00259 iaxc_video_width = width;
00260 if ( height > 0 )
00261 iaxc_video_height = height;
00262 if ( fs > 0 )
00263 iaxc_video_fragsize = fs;
00264
00265 if ( selected_call < 0 )
00266 return;
00267
00268 call = &calls[selected_call];
00269
00270 if ( !call || !call->vencoder )
00271 return;
00272
00273 call->vencoder->params_changed = 1;
00274
00275 if ( framerate > 0 )
00276 call->vencoder->framerate = framerate;
00277 if ( bitrate > 0 )
00278 call->vencoder->bitrate = bitrate;
00279 if ( width > 0 )
00280 call->vencoder->width = width;
00281 if ( height > 0 )
00282 call->vencoder->height = height;
00283 if ( fs > 0 )
00284 call->vencoder->fragsize = fs;
00285 }
00286
00287 static void reset_codec_stats(struct iaxc_video_codec *vcodec)
00288 {
00289 if ( !vcodec )
00290 return;
00291
00292 memset(&vcodec->video_stats, 0, sizeof(struct iaxc_video_stats));
00293 gettimeofday(&vcodec->video_stats.start_time, 0);
00294 }
00295
00296 static void reset_video_stats(struct iaxc_call *call)
00297 {
00298 if ( !call )
00299 return;
00300
00301 reset_codec_stats(call->vdecoder);
00302 reset_codec_stats(call->vencoder);
00303 }
00304
00305
00306
00307
00308
00309
00310 static int get_stats(struct iaxc_call *call, struct iaxc_video_stats *stats,
00311 int reset)
00312 {
00313 if ( !call || !stats )
00314 return -1;
00315
00316 memset(stats, 0, sizeof(*stats));
00317
00318 if ( call->vencoder )
00319 {
00320 stats->sent_slices = call->vencoder->video_stats.sent_slices;
00321 stats->acc_sent_size = call->vencoder->video_stats.acc_sent_size;
00322 stats->outbound_frames = call->vencoder->video_stats.outbound_frames;
00323 stats->avg_outbound_bps = call->vencoder->video_stats.avg_outbound_bps;
00324 stats->avg_outbound_fps = call->vencoder->video_stats.avg_outbound_fps;
00325 }
00326
00327 if ( call->vdecoder )
00328 {
00329 stats->received_slices = call->vdecoder->video_stats.received_slices;
00330 stats->acc_recv_size = call->vdecoder->video_stats.acc_recv_size;
00331 stats->inbound_frames = call->vdecoder->video_stats.inbound_frames;
00332 stats->dropped_frames = call->vdecoder->video_stats.dropped_frames;
00333 stats->avg_inbound_bps = call->vdecoder->video_stats.avg_inbound_bps;
00334 stats->avg_inbound_fps = call->vdecoder->video_stats.avg_inbound_fps;
00335 }
00336
00337 if ( reset )
00338 reset_video_stats(call);
00339
00340 return 0;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 static struct iaxc_video_codec *create_codec(int format, int encode)
00361 {
00362 struct iaxc_video_codec * vcodec = 0;
00363
00364 iaxci_usermsg(IAXC_TEXT_TYPE_NOTICE, "Creating codec format 0x%x",
00365 format);
00366
00367 switch ( format )
00368 {
00369 case IAXC_FORMAT_H261:
00370 case IAXC_FORMAT_H263:
00371 case IAXC_FORMAT_H263_PLUS:
00372 case IAXC_FORMAT_MPEG4:
00373 case IAXC_FORMAT_H264:
00374 #ifdef USE_FFMPEG
00375 vcodec = codec_video_ffmpeg_new(format,
00376 iaxc_video_width,
00377 iaxc_video_height,
00378 iaxc_video_framerate,
00379 iaxc_video_bitrate,
00380 iaxc_video_fragsize);
00381 #endif
00382 break;
00383
00384 case IAXC_FORMAT_THEORA:
00385 #ifdef USE_THEORA
00386 vcodec = codec_video_theora_new(format,
00387 iaxc_video_width,
00388 iaxc_video_height,
00389 iaxc_video_framerate,
00390 iaxc_video_bitrate,
00391 iaxc_video_fragsize);
00392 #endif
00393 break;
00394 }
00395
00396 reset_codec_stats(vcodec);
00397
00398 return vcodec;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 void show_video_frame(char *videobuf, int size, int cn, int source, int encoded,
00417 unsigned int ts, int rgb32)
00418 {
00419 iaxc_event e;
00420 char * buffer;
00421
00422 e.type = IAXC_EVENT_VIDEO;
00423 e.ev.video.ts = ts;
00424
00425 if ( size <= 0 )
00426 fprintf(stderr, "WARNING: size %d in show_video_frame\n", size);
00427
00428 if ( !encoded && rgb32 )
00429 {
00430 e.ev.video.size = iaxc_video_height * iaxc_video_width * 4;
00431 buffer = (char *)malloc(e.ev.video.size);
00432 assert(buffer);
00433 e.ev.video.data = buffer;
00434 iaxc_YUV420_to_RGB32(iaxc_video_width, iaxc_video_height,
00435 videobuf, buffer);
00436 } else
00437 {
00438 buffer = (char *)malloc(size);
00439 assert(buffer);
00440 memcpy(buffer, videobuf, size);
00441 e.ev.video.data = buffer;
00442 e.ev.video.size = size;
00443 }
00444
00445 e.ev.video.format = iaxc_video_format_preferred;
00446 e.ev.video.width = iaxc_video_width;
00447 e.ev.video.height = iaxc_video_height;
00448 e.ev.video.callNo = cn;
00449 e.ev.video.encoded = encoded;
00450 assert(source == IAXC_SOURCE_REMOTE || source == IAXC_SOURCE_LOCAL);
00451 e.ev.video.source = source;
00452
00453 iaxci_post_event(e);
00454 }
00455
00456
00457 int video_send_video(struct iaxc_call *call, int sel_call)
00458 {
00459 static struct slice_set_t slice_set;
00460 int format;
00461 int i = 0;
00462 const int inlen = iaxc_video_width * iaxc_video_height * 6 / 4;
00463 char * videobuf;
00464 struct timeval now;
00465 long time;
00466
00467 video_driver.input(&video_driver, &videobuf);
00468
00469
00470
00471
00472 if ( !videobuf || (iaxc_video_prefs & IAXC_VIDEO_PREF_CAPTURE_DISABLE) )
00473 return 0;
00474
00475
00476 if ( iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_LOCAL_RAW )
00477 {
00478 show_video_frame(videobuf, inlen, -1, IAXC_SOURCE_LOCAL, 0, 0,
00479 iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_RGB32);
00480 }
00481
00482 if ( sel_call < 0 || !call ||
00483 !(call->state & (IAXC_CALL_STATE_COMPLETE |
00484 IAXC_CALL_STATE_OUTGOING)) )
00485 {
00486 return -1;
00487 }
00488
00489
00490 format = call->vformat;
00491
00492 if ( format == 0 )
00493 {
00494
00495 return -1;
00496 }
00497
00498
00499
00500 if ( ( !(iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_LOCAL_ENCODED) &&
00501 (iaxc_video_prefs & IAXC_VIDEO_PREF_SEND_DISABLE) ) ||
00502 (format == 0) )
00503 {
00504 if ( call->vencoder )
00505 {
00506
00507 fprintf(stderr, "Destroying codec %s\n", call->vencoder->name);
00508 call->vencoder->destroy(call->vencoder);
00509 call->vencoder = NULL;
00510 }
00511 return 0;
00512 }else
00513 {
00514
00515 if ( call->vencoder &&
00516 (call->vencoder->format != format || call->vencoder->params_changed)
00517 )
00518 {
00519 call->vencoder->destroy(call->vencoder);
00520 call->vencoder = NULL;
00521 }
00522
00523
00524 if ( !call->vencoder )
00525 {
00526 call->vencoder = create_codec(format, 1);
00527 fprintf(stderr,"**** Created encoder codec %s\n",call->vencoder->name);
00528 }
00529
00530 if ( !call->vencoder )
00531 {
00532 fprintf(stderr,
00533 "ERROR: Video codec could not be created: 0x%08x\n",
00534 format);
00535 return -1;
00536 }
00537
00538
00539 if ( call->vencoder->encode(call->vencoder, inlen, videobuf,
00540 &slice_set) )
00541 {
00542 fprintf(stderr, "video_send_video: encode failed\n");
00543 return -1;
00544 }
00545 }
00546
00547
00548 gettimeofday(&now, 0);
00549 call->vencoder->video_stats.outbound_frames++;
00550 time = iaxci_msecdiff(&now, &call->vencoder->video_stats.start_time);
00551 if ( time > 0 )
00552 call->vencoder->video_stats.avg_outbound_fps =
00553 (float)call->vencoder->video_stats.outbound_frames *
00554 1000 / time;
00555
00556
00557
00558 if ( !call->session )
00559 return -1;
00560
00561 for ( i = 0; i < slice_set.num_slices; i++ )
00562 {
00563
00564
00565 if ( iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_LOCAL_ENCODED )
00566 {
00567 show_video_frame(slice_set.data[i], slice_set.size[i],
00568 -1, IAXC_SOURCE_LOCAL, 1, 0, 0);
00569 }
00570
00571 if ( !(iaxc_video_prefs & IAXC_VIDEO_PREF_SEND_DISABLE) )
00572 {
00573 if ( iax_send_video_trunk(call->session, format,
00574 slice_set.data[i],
00575 slice_set.size[i],
00576 0, i) == -1 )
00577 {
00578 fprintf(stderr, "Failed to send a slice, call %d, size %d\n",
00579 sel_call, slice_set.size[i]);
00580 return -1;
00581 }
00582
00583
00584 call->vencoder->video_stats.sent_slices++;
00585 call->vencoder->video_stats.acc_sent_size +=
00586 slice_set.size[i];
00587 if ( time > 0 )
00588 call->vencoder->video_stats.avg_outbound_bps =
00589 call->vencoder->video_stats.acc_sent_size *
00590 8000 / time;
00591 }
00592 }
00593
00594 return 0;
00595 }
00596
00597
00598 int video_recv_video(struct iaxc_call *call, int sel_call,
00599 void *encoded_video, int encoded_video_len,
00600 unsigned int ts, int format)
00601 {
00602 static char videobuf[VIDEO_BUFSIZ];
00603 int outsize = VIDEO_BUFSIZ;
00604 int ret_dec;
00605 struct timeval now;
00606 long time;
00607
00608 if ( !call )
00609 return 0;
00610
00611 if ( format == 0 )
00612 {
00613 fprintf(stderr, "video_recv_video: Format is zero (should't happen)!\n");
00614 return -1;
00615 }
00616
00617
00618 if ( iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_REMOTE_ENCODED )
00619 {
00620 show_video_frame((char *)encoded_video, encoded_video_len, -1,
00621 IAXC_SOURCE_REMOTE, 1, ts, 0);
00622 }
00623
00624
00625 if ( call->vdecoder && call->vdecoder->format != format )
00626 {
00627 call->vdecoder->destroy(call->vdecoder);
00628 call->vdecoder = NULL;
00629 }
00630
00631
00632 if ( !(iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_REMOTE_RAW) )
00633 return 0;
00634
00635
00636 if ( !call->vdecoder )
00637 {
00638 call->vdecoder = create_codec(format, 0);
00639 fprintf(stderr,"**** Created decoder codec %s\n",call->vdecoder->name);
00640 }
00641
00642 if ( !call->vdecoder )
00643 {
00644 fprintf(stderr, "ERROR: Video codec could not be created: %d\n",
00645 format);
00646 return -1;
00647 }
00648
00649
00650 gettimeofday(&now, 0);
00651 time = iaxci_msecdiff(&now, &call->vdecoder->video_stats.start_time);
00652 call->vdecoder->video_stats.received_slices++;
00653 call->vdecoder->video_stats.acc_recv_size += encoded_video_len;
00654 if ( time > 0 )
00655 call->vdecoder->video_stats.avg_inbound_bps =
00656 call->vdecoder->video_stats.acc_recv_size * 8000 / time;
00657
00658 ret_dec = call->vdecoder->decode(call->vdecoder, encoded_video_len,
00659 (char *)encoded_video, &outsize, videobuf);
00660
00661 if ( ret_dec < 0 )
00662 {
00663 fprintf(stderr, "ERROR: decode error\n");
00664 return -1;
00665 }
00666 else if ( ret_dec > 0 )
00667 {
00668
00669
00670
00671 return 0;
00672 }
00673
00674
00675 call->vdecoder->video_stats.inbound_frames++;
00676 if ( time > 0 )
00677 call->vdecoder->video_stats.avg_inbound_fps =
00678 call->vdecoder->video_stats.inbound_frames *
00679 1000.0F / time;
00680
00681 if ( outsize > 0 )
00682 {
00683 show_video_frame(videobuf, outsize, sel_call,
00684 IAXC_SOURCE_REMOTE, 0, ts,
00685 iaxc_video_prefs & IAXC_VIDEO_PREF_RECV_RGB32);
00686 }
00687
00688 return 0;
00689 }
00690
00691 int video_initialize(void)
00692 {
00693 if ( pv_initialize(&video_driver, iaxc_video_width, iaxc_video_height,
00694 iaxc_video_framerate) )
00695 {
00696 fprintf(stderr, "ERROR: cannot initialize pv\n");
00697 return -1;
00698 }
00699
00700
00701
00702
00703 iaxc_set_video_prefs(iaxc_video_prefs);
00704
00705 return 0;
00706 }
00707
00708 int video_destroy(void)
00709 {
00710 if ( video_driver.destroy )
00711 return video_driver.destroy(&video_driver);
00712 else
00713 return -1;
00714 }
00715
00716
00717
00718
00719
00720 #define CLIP_SIZE 811
00721 #define CLIP_OFFSET 277
00722
00723 #define YMUL 298
00724 #define RMUL 409
00725 #define BMUL 516
00726 #define G1MUL -100
00727 #define G2MUL -208
00728
00729 static int yuv2rgb_y[256];
00730 static int yuv2rgb_r[256];
00731 static int yuv2rgb_b[256];
00732 static int yuv2rgb_g1[256];
00733 static int yuv2rgb_g2[256];
00734 static unsigned long yuv2rgb_clip[CLIP_SIZE];
00735 static unsigned long yuv2rgb_clip8[CLIP_SIZE];
00736 static unsigned long yuv2rgb_clip16[CLIP_SIZE];
00737 static int yuv2rgb_tables_initialized = 0;
00738
00739 #define RED(y, v) yuv2rgb_clip16[CLIP_OFFSET + yuv2rgb_y[y] + yuv2rgb_r[v]]
00740 #define GREEN(y,v,u) yuv2rgb_clip8[CLIP_OFFSET + yuv2rgb_y[y] + yuv2rgb_g1[v] + yuv2rgb_g2[u]]
00741 #define BLUE(y,u) yuv2rgb_clip[CLIP_OFFSET + yuv2rgb_y[y] + yuv2rgb_b[u]]
00742
00743 static void iaxc_init_yuv2rgb_tables(void)
00744 {
00745 int i;
00746
00747 for (i = 0; i < 256; i++)
00748 {
00749 yuv2rgb_y[i] = (YMUL * (i - 16) + 128) >> 8;
00750 yuv2rgb_r[i] = (RMUL * (i - 128)) >> 8;
00751 yuv2rgb_b[i] = (BMUL * (i - 128)) >> 8;
00752 yuv2rgb_g1[i] = (G1MUL * (i - 128)) >> 8;
00753 yuv2rgb_g2[i] = (G2MUL * (i - 128)) >> 8;
00754 }
00755 for ( i = 0 ; i < CLIP_OFFSET ; i++ )
00756 {
00757 yuv2rgb_clip[i] = 0;
00758 yuv2rgb_clip8[i] = 0;
00759 yuv2rgb_clip16[i] = 0;
00760 }
00761 for ( ; i < CLIP_OFFSET + 256 ; i++ )
00762 {
00763 yuv2rgb_clip[i] = i - CLIP_OFFSET;
00764 yuv2rgb_clip8[i] = (i - CLIP_OFFSET) << 8;
00765 yuv2rgb_clip16[i] = (i - CLIP_OFFSET) << 16;
00766 }
00767 for ( ; i < CLIP_SIZE ; i++ )
00768 {
00769 yuv2rgb_clip[i] = 255;
00770 yuv2rgb_clip8[i] = 255 << 8;
00771 yuv2rgb_clip16[i] = 255 << 16;
00772 }
00773
00774 yuv2rgb_tables_initialized = 1;
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 void iaxc_YUV420_to_RGB32(int width, int height, char *src, char *dest)
00787 {
00788 unsigned char *y, *u, *v;
00789 unsigned int *dst;
00790 int i;
00791
00792 if ( !yuv2rgb_tables_initialized )
00793 iaxc_init_yuv2rgb_tables();
00794
00795 dst = (unsigned int *)dest;
00796 y = (unsigned char *)src;
00797 u = y + width * height;
00798 v = u + width * height / 4;
00799
00800 for (i = 0; i < height; i++)
00801 {
00802 unsigned char *uu,*vv;
00803 unsigned int *d;
00804 int j;
00805
00806 d = dst;
00807 uu = u;
00808 vv = v;
00809 for ( j = 0; j < width >> 1; j++ )
00810 {
00811 *(d++) = 0xff000000 |
00812 RED(*y,*vv) |
00813 GREEN(*y,*vv,*uu) |
00814 BLUE(*y,*uu);
00815 y++;
00816 *(d++) = 0xff000000 |
00817 RED(*y,*vv) |
00818 GREEN(*y,*vv,*uu) |
00819 BLUE(*y,*uu);
00820 y++;
00821 uu++;
00822 vv++;
00823 }
00824 if ( i & 1 )
00825 {
00826 u += width >> 1;
00827 v += width >> 1;
00828 }
00829 dst += width;
00830 }
00831 }
00832
00833 int iaxc_is_camera_working()
00834 {
00835 return video_driver.is_camera_working(&video_driver);
00836 }
00837
00838 int video_send_stats(struct iaxc_call * call)
00839 {
00840 const long video_stats_interval = 1000;
00841 static struct timeval video_stats_start = {0, 0};
00842 iaxc_event e;
00843 struct timeval now;
00844
00845 if ( !call )
00846 return -1;
00847
00848 if ( video_stats_start.tv_sec == 0 && video_stats_start.tv_usec == 0 )
00849 gettimeofday(&video_stats_start, 0);
00850
00851 gettimeofday(&now, 0);
00852
00853 if ( iaxci_msecdiff(&now, &video_stats_start) > video_stats_interval )
00854 {
00855 get_stats(call, &e.ev.videostats.stats, 1);
00856 e.type = IAXC_EVENT_VIDEOSTATS;
00857 e.ev.videostats.callNo = selected_call;
00858 iaxci_post_event(e);
00859
00860 video_stats_start = now;
00861 }
00862
00863 return 0;
00864 }
00865