import the recent additions for video console into trunk,
[asterisk/asterisk.git] / channels / console_video.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright 2007-2008, Marta Carbone, Sergio Fadda, Luigi Rizzo
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*
18  * Experimental support for video sessions. We use SDL for rendering, ffmpeg
19  * as the codec library for encoding and decoding, and Video4Linux and X11
20  * to generate the local video stream.
21  *
22  * If one of these pieces is not available, either at compile time or at
23  * runtime, we do our best to run without it. Of course, no codec library
24  * means we can only deal with raw data, no SDL means we cannot do rendering,
25  * no V4L or X11 means we cannot generate data (but in principle we could
26  * stream from or record to a file).
27  *
28  * We need a recent (2007.07.12 or newer) version of ffmpeg to avoid warnings.
29  * Older versions might give 'deprecated' messages during compilation,
30  * thus not compiling in AST_DEVMODE, or don't have swscale, in which case
31  * you can try to compile #defining OLD_FFMPEG here.
32  *
33  * $Revision$
34  */
35
36 //#define DROP_PACKETS 5       /* if set, drop this % of video packets */
37 //#define OLD_FFMPEG    1       /* set for old ffmpeg with no swscale */
38
39 #include "asterisk.h"
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41 #include <sys/ioctl.h>
42 #include "asterisk/cli.h"
43 #include "asterisk/file.h"
44 #include "asterisk/channel.h"
45
46 #include "console_video.h"
47
48 /*
49 The code is structured as follows.
50
51 When a new console channel is created, we call console_video_start()
52 to initialize SDL, the source, and the encoder/ decoder for the
53 formats in use (XXX the latter two should be done later, once the
54 codec negotiation is complete).  Also, a thread is created to handle
55 the video source and generate frames.
56
57 While communication is on, the local source is generated by the
58 video thread, which wakes up periodically, generates frames and
59 enqueues them in chan->readq.  Incoming rtp frames are passed to
60 console_write_video(), decoded and passed to SDL for display.
61
62 For as unfortunate and confusing as it can be, we need to deal with a
63 number of different video representations (size, codec/pixel format,
64 codec parameters), as follows:
65
66  loc_src        is the data coming from the camera/X11/etc.
67         The format is typically constrained by the video source.
68
69  enc_in         is the input required by the encoder.
70         Typically constrained in size by the encoder type.
71
72  enc_out        is the bitstream transmitted over RTP.
73         Typically negotiated while the call is established.
74
75  loc_dpy        is the format used to display the local video source.
76         Depending on user preferences this can have the same size as
77         loc_src_fmt, or enc_in_fmt, or thumbnail size (e.g. PiP output)
78
79  dec_in         is the incoming RTP bitstream. Negotiated
80         during call establishment, it is not necessarily the same as
81         enc_in_fmt
82
83  dec_out        the output of the decoder.
84         The format is whatever the other side sends, and the
85         buffer is allocated by avcodec_decode_... so we only
86         copy the data here.
87
88  rem_dpy        the format used to display the remote stream
89
90  src_dpy        is the format used to display the local video source streams
91         The number of these fbuf_t is determined at run time, with dynamic allocation
92
93 We store the format info together with the buffer storing the data.
94 As a future optimization, a format/buffer may reference another one
95 if the formats are equivalent. This will save some unnecessary format
96 conversion.
97
98
99 In order to handle video you need to add to sip.conf (and presumably
100 iax.conf too) the following:
101
102         [general](+)
103                 videosupport=yes
104                 allow=h263      ; this or other video formats
105                 allow=h263p     ; this or other video formats
106
107  */
108
109 /*
110  * Codecs are absolutely necessary or we cannot do anything.
111  * SDL is optional (used for rendering only), so that we can still
112  * stream video withouth displaying it.
113  */
114 #if !defined(HAVE_VIDEO_CONSOLE) || !defined(HAVE_FFMPEG)
115 /* stubs if required pieces are missing */
116 int console_write_video(struct ast_channel *chan, struct ast_frame *f)
117 {
118         return 0;       /* writing video not supported */
119 }
120
121 int console_video_cli(struct video_desc *env, const char *var, int fd)
122 {
123         return 1;       /* nothing matched */
124 }
125
126 int console_video_config(struct video_desc **penv, const char *var, const char *val)
127 {
128         return 1;       /* no configuration */
129 }
130
131 void console_video_start(struct video_desc *env, struct ast_channel *owner)
132 {
133         ast_log(LOG_NOTICE, "voice only, console video support not present\n");
134 }
135
136 void console_video_uninit(struct video_desc *env)
137 {
138 }
139
140 int console_video_formats = 0;
141
142 #else /* defined(HAVE_FFMPEG) && defined(HAVE_SDL) */
143
144 /*! The list of video formats we support. */
145 int console_video_formats = 
146         AST_FORMAT_H263_PLUS | AST_FORMAT_H263 |
147         AST_FORMAT_MP4_VIDEO | AST_FORMAT_H264 | AST_FORMAT_H261 ;
148
149
150
151 /* function to scale and encode buffers */
152 static void my_scale(struct fbuf_t *in, AVPicture *p_in,
153         struct fbuf_t *out, AVPicture *p_out);
154
155 /*
156  * this structure will be an entry in the table containing
157  * every device specified in the file oss.conf, it contains various infomation
158  * about the device
159  */
160 struct video_device {
161         char                    *name;          /* name of the device                   */
162         /* allocated dynamically (see fill_table function) */
163         struct grab_desc        *grabber;       /* the grabber for the device type      */
164         void                    *grabber_data;  /* device's private data structure      */
165         struct fbuf_t           *dev_buf;       /* buffer for incoming data             */
166         struct timeval          last_frame;     /* when we read the last frame ?        */
167         int                     status_index;   /* what is the status of the device (source) */
168         /* status index is set using the IS_ON, IS_PRIMARY and IS_SECONDARY costants */
169         /* status_index is the index of the status message in the src_msgs array in console_gui.c */
170 };
171
172 struct video_codec_desc;        /* forward declaration */
173 /*
174  * Descriptor of the local source, made of the following pieces:
175  *  + configuration info (geometry, device name, fps...). These are read
176  *    from the config file and copied here before calling video_out_init();
177  *  + the frame buffer (buf) and source pixel format, allocated at init time;
178  *  + the encoding and RTP info, including timestamps to generate
179  *    frames at the correct rate;
180  *  + source-specific info, i.e. fd for /dev/video, dpy-image for x11, etc,
181  *    filled in by grabber_open, part of source_specific information are in 
182  *    the device table (devices member), others are shared;
183  * NOTE: loc_src.data == NULL means the rest of the struct is invalid, and
184  *      the video source is not available.
185  */
186 struct video_out_desc {
187         /* video device support.
188          * videodevice and geometry are read from the config file.
189          * At the right time we try to open it and allocate a buffer.
190          * If we are successful, webcam_bufsize > 0 and we can read.
191          */
192         /* all the following is config file info copied from the parent */
193         int             fps;
194         int             bitrate;
195         int             qmin;
196
197         int sendvideo;
198
199         struct fbuf_t   loc_src_geometry;       /* local source geometry only (from config file) */
200         struct fbuf_t   enc_out;        /* encoder output buffer, allocated in video_out_init() */
201
202         struct video_codec_desc *enc;   /* encoder */
203         void            *enc_ctx;       /* encoding context */
204         AVCodec         *codec;
205         AVFrame         *enc_in_frame;  /* enc_in mapped into avcodec format. */
206                                         /* The initial part of AVFrame is an AVPicture */
207         int             mtu;
208         
209         /* Table of devices specified with "videodevice=" in oss.conf.
210          * Static size as we have a limited number of entries.
211          */
212         struct video_device     devices[MAX_VIDEO_SOURCES]; 
213         int                     device_num; /*number of devices in table*/
214         int                     device_primary; /*index of the actual primary device in the table*/
215         int                     device_secondary; /*index of the actual secondary device in the table*/
216
217         int                     picture_in_picture; /*Is the PiP mode activated? 0 = NO | 1 = YES*/
218
219         /* these are the coordinates of the picture inside the picture (visible if PiP mode is active) 
220         these coordinates are valid considering the containing buffer with cif geometry*/
221         int                     pip_x;
222         int                     pip_y;
223 };
224
225 /*
226  * The overall descriptor, with room for config info, video source and
227  * received data descriptors, SDL info, etc.
228  * This should be globally visible to all modules (grabber, vcodecs, gui)
229  * and contain all configurtion info.
230  */
231 struct video_desc {
232         char                    codec_name[64]; /* the codec we use */
233
234         int                     stayopen;       /* set if gui starts manually */
235         pthread_t               vthread;        /* video thread */
236         ast_mutex_t             dec_lock;       /* sync decoder and video thread */
237         int                     shutdown;       /* set to shutdown vthread */
238         struct ast_channel      *owner;         /* owner channel */
239
240
241         struct fbuf_t   enc_in;         /* encoder input buffer, allocated in video_out_init() */
242
243         char                    keypad_file[256];       /* image for the keypad */
244         char                    keypad_font[256];       /* font for the keypad */
245
246         char                    sdl_videodriver[256];
247
248         struct fbuf_t           rem_dpy;        /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
249         struct fbuf_t           loc_dpy;        /* display local source, no buffer (managed by SDL in bmp[1]) */
250
251         /*display for  sources in additional windows, 
252         ideally infinite additional sources could be present
253         pratically we assume a maximum of 9 sources to show*/
254         struct fbuf_t           src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
255         
256         /* local information for grabbers, codecs, gui */
257         struct gui_info         *gui;
258         struct video_dec_desc   *in;            /* remote video descriptor */
259         struct video_out_desc   out;            /* local video descriptor */
260 };
261
262 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
263
264 void fbuf_free(struct fbuf_t *b)
265 {
266         struct fbuf_t x = *b;
267
268         if (b->data && b->size)
269                 ast_free(b->data);
270         bzero(b, sizeof(*b));
271         /* restore some fields */
272         b->w = x.w;
273         b->h = x.h;
274         b->pix_fmt = x.pix_fmt;
275 }
276
277 #if 0
278 /* helper function to print the amount of memory used by the process.
279  * Useful to track memory leaks, unfortunately this code is OS-specific
280  * so we keep it commented out.
281  */
282 static int
283 used_mem(const char *msg)
284 {
285         char in[128];
286
287         pid_t pid = getpid();
288         sprintf(in, "ps -o vsz= -o rss= %d", pid);
289         ast_log(LOG_WARNING, "used mem (vsize, rss) %s ", msg);
290         system(in);
291         return 0;
292 }
293 #endif
294         
295 #include "vcodecs.c"
296 #include "console_gui.c"
297
298 /*! \brief Try to open video sources, return 0 on success, 1 on error
299  * opens all video sources found in the oss.conf configuration files.
300  * Saves the grabber and the datas in the device table (in the devices field
301  * of the descriptor referenced by v).
302  * Initializes the device_primary and device_secondary
303  * fields of v with the first devices that was
304  * successfully opened.
305  *
306  * \param v = video out environment descriptor
307  *
308  * returns 0 on success, 1 on error 
309 */
310 static int grabber_open(struct video_out_desc *v)
311 {
312         struct grab_desc *g;
313         void *g_data;
314         int i, j;
315
316         /* for each device in the device table... */
317         for (i = 0; i < v->device_num; i++) {
318                 /* device already open */
319                 if (v->devices[i].grabber)
320                         continue;
321                 /* for each type of grabber supported... */
322                 for (j = 0; (g = console_grabbers[j]); j++) {
323                         /* the grabber is opened and the informations saved in the device table */
324                         g_data = g->open(v->devices[i].name, &v->loc_src_geometry, v->fps);
325                         if (!g_data)
326                                 continue;
327                         v->devices[i].grabber = g;
328                         v->devices[i].grabber_data = g_data;
329                         v->devices[i].status_index |= IS_ON;
330                 }
331         }
332         /* the first working device is selected as the primary one and the secondary one */
333         for (i = 0; i < v->device_num; i++) {
334                 if (!v->devices[i].grabber) 
335                         continue;
336                 v->device_primary = i;
337                 v->device_secondary = i;
338                 return 0; /* source found */
339         }
340         return 1; /* no source found */
341 }
342
343
344 /*! \brief complete a buffer from the specified local video source.
345  * Called by get_video_frames(), in turn called by the video thread.
346  *
347  * \param dev = video environment descriptor
348  * \param fps = frame per seconds, for every device
349  *
350  * returns:
351  * - NULL on falure
352  * - reference to the device buffer on success
353  */
354 static struct fbuf_t *grabber_read(struct video_device *dev, int fps)
355 {
356         struct timeval now = ast_tvnow();
357
358         if (dev->grabber == NULL) /* not initialized */
359                 return NULL;
360         
361         /* the last_frame field in this row of the device table (dev)
362         is always initialized, it is set during the parsing of the config
363         file, and never unset, function fill_device_table(). */
364         /* check if it is time to read */
365         if (ast_tvdiff_ms(now, dev->last_frame) < 1000/fps)
366                 return NULL; /* too early */
367         dev->last_frame = now; /* XXX actually, should correct for drift */
368         return dev->grabber->read(dev->grabber_data);
369 }
370
371 /*! \brief handler run when dragging with the left button on
372  * the local source window - the effect is to move the offset
373  * of the captured area.
374  */
375 static void grabber_move(struct video_device *dev, int dx, int dy)
376 {
377         if (dev->grabber && dev->grabber->move)
378                 dev->grabber->move(dev->grabber_data, dx, dy);
379 }
380
381 /*
382  * Map the codec name to the library. If not recognised, use a default.
383  * This is useful in the output path where we decide by name, presumably.
384  */
385 static struct video_codec_desc *map_config_video_format(char *name)
386 {
387         int i;
388
389         for (i = 0; supported_codecs[i]; i++)
390                 if (!strcasecmp(name, supported_codecs[i]->name))
391                         break;
392         if (supported_codecs[i] == NULL) {
393                 ast_log(LOG_WARNING, "Cannot find codec for '%s'\n", name);
394                 i = 0;
395                 strcpy(name, supported_codecs[i]->name);
396         }
397         ast_log(LOG_WARNING, "Using codec '%s'\n", name);
398         return supported_codecs[i];
399 }
400
401
402 /*! \brief uninitialize the descriptor for local video stream */
403 static int video_out_uninit(struct video_desc *env)
404 {
405         struct video_out_desc *v = &env->out;
406         int i; /* integer variable used as iterator */
407         
408         /* XXX this should be a codec callback */
409         if (v->enc_ctx) {
410                 AVCodecContext *enc_ctx = (AVCodecContext *)v->enc_ctx;
411                 avcodec_close(enc_ctx);
412                 av_free(enc_ctx);
413                 v->enc_ctx = NULL;
414         }
415         if (v->enc_in_frame) {
416                 av_free(v->enc_in_frame);
417                 v->enc_in_frame = NULL;
418         }
419         v->codec = NULL;        /* nothing to free, this is only a reference */
420         /* release the buffers */
421         fbuf_free(&env->enc_in);
422         fbuf_free(&v->enc_out);
423         /* close the grabbers */
424         for (i = 0; i < v->device_num; i++) {
425                 if (v->devices[i].grabber){
426                         v->devices[i].grabber_data =
427                                 v->devices[i].grabber->close(v->devices[i].grabber_data);
428                         v->devices[i].grabber = NULL;
429                         /* dev_buf is already freed by grabber->close() */
430                         v->devices[i].dev_buf = NULL;
431                 }
432                 v->devices[i].status_index = 0;
433         }
434         v->picture_in_picture = 0;
435         return -1;
436 }
437
438 /*
439  * Initialize the encoder for the local source:
440  * - enc_ctx, codec, enc_in_frame are used by ffmpeg for encoding;
441  * - enc_out is used to store the encoded frame (to be sent)
442  * - mtu is used to determine the max size of video fragment
443  * NOTE: we enter here with the video source already open.
444  */
445 static int video_out_init(struct video_desc *env)
446 {
447         int codec;
448         int size;
449         struct fbuf_t *enc_in;
450         struct video_out_desc *v = &env->out;
451
452         v->enc_ctx              = NULL;
453         v->codec                = NULL;
454         v->enc_in_frame         = NULL;
455         v->enc_out.data         = NULL;
456
457         codec = map_video_format(v->enc->format, CM_WR);
458         v->codec = avcodec_find_encoder(codec);
459         if (!v->codec) {
460                 ast_log(LOG_WARNING, "Cannot find the encoder for format %d\n",
461                         codec);
462                 return -1;      /* error, but nothing to undo yet */
463         }
464
465         v->mtu = 1400;  /* set it early so the encoder can use it */
466
467         /* allocate the input buffer for encoding.
468          * ffmpeg only supports PIX_FMT_YUV420P for the encoding.
469          */
470         enc_in = &env->enc_in;
471         enc_in->pix_fmt = PIX_FMT_YUV420P;
472         enc_in->size = (enc_in->w * enc_in->h * 3)/2;
473         enc_in->data = ast_calloc(1, enc_in->size);
474         if (!enc_in->data) {
475                 ast_log(LOG_WARNING, "Cannot allocate encoder input buffer\n");
476                 return video_out_uninit(env);
477         }
478         /* construct an AVFrame that points into buf_in */
479         v->enc_in_frame = avcodec_alloc_frame();
480         if (!v->enc_in_frame) {
481                 ast_log(LOG_WARNING, "Unable to allocate the encoding video frame\n");
482                 return video_out_uninit(env);
483         }
484
485         /* parameters for PIX_FMT_YUV420P */
486         size = enc_in->w * enc_in->h;
487         v->enc_in_frame->data[0] = enc_in->data;
488         v->enc_in_frame->data[1] = v->enc_in_frame->data[0] + size;
489         v->enc_in_frame->data[2] = v->enc_in_frame->data[1] + size/4;
490         v->enc_in_frame->linesize[0] = enc_in->w;
491         v->enc_in_frame->linesize[1] = enc_in->w/2;
492         v->enc_in_frame->linesize[2] = enc_in->w/2;
493
494         /* now setup the parameters for the encoder.
495          * XXX should be codec-specific
496          */
497     {
498         AVCodecContext *enc_ctx = avcodec_alloc_context();
499         v->enc_ctx = enc_ctx;
500         enc_ctx->pix_fmt = enc_in->pix_fmt;
501         enc_ctx->width = enc_in->w;
502         enc_ctx->height = enc_in->h;
503         /* XXX rtp_callback ?
504          * rtp_mode so ffmpeg inserts as many start codes as possible.
505          */
506         enc_ctx->rtp_mode = 1;
507         enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
508         enc_ctx->bit_rate = v->bitrate;
509         enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
510         enc_ctx->qmin = v->qmin;        /* should be configured */
511         enc_ctx->time_base = (AVRational){1, v->fps};
512         enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
513
514         v->enc->enc_init(v->enc_ctx);
515  
516         if (avcodec_open(enc_ctx, v->codec) < 0) {
517                 ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
518                         codec);
519                 av_free(enc_ctx);
520                 v->enc_ctx = NULL;
521                 return video_out_uninit(env);
522         }
523     }
524         /*
525          * Allocate enough for the encoded bitstream. As we are compressing,
526          * we hope that the output is never larger than the input size.
527          */
528         v->enc_out.data = ast_calloc(1, enc_in->size);
529         v->enc_out.size = enc_in->size;
530         v->enc_out.used = 0;
531
532         return 0;
533 }
534
535 /*! \brief possibly uninitialize the video console.
536  * Called at the end of a call, should reset the 'owner' field,
537  * then possibly terminate the video thread if the gui has
538  * not been started manually.
539  * In practice, signal the thread and give it a bit of time to
540  * complete, giving up if it gets stuck. Because uninit
541  * is called from hangup with the channel locked, and the thread
542  * uses the chan lock, we need to unlock here. This is unsafe,
543  * and we should really use refcounts for the channels.
544  */
545 void console_video_uninit(struct video_desc *env)
546 {
547         int i, t = 100; /* initial wait is shorter, than make it longer */
548         if (env->stayopen == 0) {       /* in a call */
549                 env->shutdown = 1;
550                 for (i=0; env->shutdown && i < 10; i++) {
551                         if (env->owner)
552                                 ast_channel_unlock(env->owner);
553                         usleep(t);
554                         t = 1000000;
555                         if (env->owner)
556                                 ast_channel_lock(env->owner);
557                 }
558         }
559         env->owner = NULL;      /* this is unconditional */
560 }
561
562 /*! fill an AVPicture from our fbuf info, as it is required by
563  * the image conversion routines in ffmpeg. Note that the pointers
564  * are recalculated if the fbuf has an offset (and so represents a picture in picture)
565  * XXX This depends on the format.
566  */
567 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p)
568 {
569         /* provide defaults for commonly used formats */
570         int l4 = b->w * b->h/4; /* size of U or V frame */
571         int len = b->w;         /* Y linesize, bytes */
572         int luv = b->w/2;       /* U/V linesize, bytes */
573         int sample_size = 1;
574         
575         bzero(p, sizeof(*p));
576         switch (b->pix_fmt) {
577         case PIX_FMT_RGB555:
578         case PIX_FMT_RGB565:
579                 sample_size = 2;
580                 luv = 0;
581                 break;
582         case PIX_FMT_RGBA32:
583                 sample_size = 4;
584                 luv = 0;
585                 break;
586         case PIX_FMT_YUYV422:   /* Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr */
587                 sample_size = 2;        /* all data in first plane, probably */
588                 luv = 0;
589                 break;
590         }
591         len *= sample_size;
592         
593         p->data[0] = b->data;
594         p->linesize[0] = len;
595         /* these are only valid for component images */
596         p->data[1] = luv ? b->data + 4*l4 : b->data+len;
597         p->data[2] = luv ? b->data + 5*l4 : b->data+len;
598         p->linesize[1] = luv;
599         p->linesize[2] = luv;
600         
601         /* add the offsets to the pointers previously calculated, 
602         it is necessary for the picture in picture mode */
603         p->data[0] += len*b->win_y + b->win_x*sample_size;
604         if (luv) { 
605                 p->data[1] += luv*(b->win_y/2) + (b->win_x/2) * sample_size;
606                 p->data[2] += luv*(b->win_y/2) + (b->win_x/2) * sample_size;
607         }
608         return p;
609 }
610
611 /*! convert/scale between an input and an output format.
612  * Old version of ffmpeg only have img_convert, which does not rescale.
613  * New versions use sws_scale which does both.
614  */
615 static void my_scale(struct fbuf_t *in, AVPicture *p_in,
616         struct fbuf_t *out, AVPicture *p_out)
617 {
618         AVPicture my_p_in, my_p_out;
619         int eff_w=out->w, eff_h=out->h;
620
621         if (p_in == NULL)
622                 p_in = fill_pict(in, &my_p_in);
623         if (p_out == NULL)
624                 p_out = fill_pict(out, &my_p_out);
625         
626         /*if win_w is different from zero then we must change 
627         the size of the scaled buffer (the position is already 
628         encoded into the out parameter)*/
629         if (out->win_w) { /* picture in picture enabled */
630                 eff_w=out->win_w;
631                 eff_h=out->win_h;
632         }
633 #ifdef OLD_FFMPEG
634         /* XXX img_convert is deprecated, and does not do rescaling, PiP not supported */
635         img_convert(p_out, out->pix_fmt,
636                 p_in, in->pix_fmt, in->w, in->h);
637 #else /* XXX replacement */
638     {
639         struct SwsContext *convert_ctx;
640         
641         convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
642                 eff_w, eff_h, out->pix_fmt,
643                 SWS_BICUBIC, NULL, NULL, NULL);
644         if (convert_ctx == NULL) {
645                 ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
646                 return;
647         }
648         if (0)
649                 ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
650                         in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
651         sws_scale(convert_ctx,
652                 p_in->data, p_in->linesize,
653                 in->w, in->h, /* src slice */
654                 p_out->data, p_out->linesize);
655
656         sws_freeContext(convert_ctx);
657     }
658 #endif /* XXX replacement */
659 }
660
661 struct video_desc *get_video_desc(struct ast_channel *c);
662
663 /*
664  * This function is called (by asterisk) for each video packet
665  * coming from the network (the 'in' path) that needs to be processed.
666  * We need to reconstruct the entire video frame before we can decode it.
667  * After a video packet is received we have to:
668  * - extract the bitstream with pre_process_data()
669  * - append the bitstream to a buffer
670  * - if the fragment is the last (RTP Marker) we decode it with decode_video()
671  * - after the decoding is completed we display the decoded frame with show_frame()
672  */
673 int console_write_video(struct ast_channel *chan, struct ast_frame *f);
674 int console_write_video(struct ast_channel *chan, struct ast_frame *f)
675 {
676         struct video_desc *env = get_video_desc(chan);
677         struct video_dec_desc *v = env->in;
678
679         if (!env->gui)  /* no gui, no rendering */
680                 return 0;
681         if (v == NULL)
682                 env->in = v = dec_init(f->subclass & ~1);
683         if (v == NULL) {
684                 /* This is not fatal, but we won't have incoming video */
685                 ast_log(LOG_WARNING, "Cannot initialize input decoder\n");
686                 return 0;
687         }
688
689         if (v->dec_in_cur == NULL)      /* no buffer for incoming frames, drop */
690                 return 0;
691 #if defined(DROP_PACKETS) && DROP_PACKETS > 0
692         /* Simulate lost packets */
693         if ((random() % 10000) <= 100*DROP_PACKETS) {
694                 ast_log(LOG_NOTICE, "Packet lost [%d]\n", f->seqno);
695                 return 0;
696         }
697 #endif
698         if (v->discard) {
699                 /*
700                  * In discard mode, drop packets until we find one with
701                  * the RTP marker set (which is the end of frame).
702                  * Note that the RTP marker flag is sent as the LSB of the
703                  * subclass, which is a  bitmask of formats. The low bit is
704                  * normally used for audio so there is no interference.
705                  */
706                 if (f->subclass & 0x01) {
707                         v->dec_in_cur->used = 0;
708                         v->dec_in_cur->ebit = 0;
709                         v->next_seq = f->seqno + 1;     /* wrap at 16 bit */
710                         v->discard = 0;
711                         ast_log(LOG_WARNING, "out of discard mode, frame %d\n", f->seqno);
712                 }
713                 return 0;
714         }
715
716         /*
717          * Only in-order fragments will be accepted. Remember seqno
718          * has 16 bit so there is wraparound. Also, ideally we could
719          * accept a bit of reordering, but at the moment we don't.
720          */
721         if (v->next_seq != f->seqno) {
722                 ast_log(LOG_WARNING, "discarding frame out of order, %d %d\n",
723                         v->next_seq, f->seqno);
724                 v->discard = 1;
725                 return 0;
726         }
727         v->next_seq++;
728
729         if (f->data.ptr == NULL || f->datalen < 2) {
730                 ast_log(LOG_WARNING, "empty video frame, discard\n");
731                 return 0;
732         }
733         if (v->d_callbacks->dec_decap(v->dec_in_cur, f->data.ptr, f->datalen)) {
734                 ast_log(LOG_WARNING, "error in dec_decap, enter discard\n");
735                 v->discard = 1;
736         }
737         if (f->subclass & 0x01) {       // RTP Marker
738                 /* prepare to decode: advance the buffer so the video thread knows. */
739                 struct fbuf_t *tmp = v->dec_in_cur;     /* store current pointer */
740                 ast_mutex_lock(&env->dec_lock);
741                 if (++v->dec_in_cur == &v->dec_in[N_DEC_IN])    /* advance to next, circular */
742                         v->dec_in_cur = &v->dec_in[0];
743                 if (v->dec_in_dpy == NULL) {    /* were not displaying anything, so set it */
744                         v->dec_in_dpy = tmp;
745                 } else if (v->dec_in_dpy == v->dec_in_cur) { /* current slot is busy */
746                         v->dec_in_cur = NULL;
747                 }
748                 ast_mutex_unlock(&env->dec_lock);
749         }
750         return 0;
751 }
752
753
754 /*! \brief refreshes the buffers of all the device by calling the
755  * grabber_read on each device in the device table.
756  * it encodes the primary source buffer, if the picture in picture mode is
757  * enabled it encodes (in the buffer to split) the secondary source buffer too.
758  * The encoded buffer is splitted to build the local and the remote view.
759  * Return a list of ast_frame representing the video fragments.
760  * The head pointer is returned by the function, the tail pointer
761  * is returned as an argument.
762  *
763  * \param env = video environment descriptor
764  * \param tail = tail ponter (pratically a return value)
765  */
766 static struct ast_frame *get_video_frames(struct video_desc *env, struct ast_frame **tail)
767 {
768         struct video_out_desc *v = &env->out;
769         struct ast_frame *dummy;
770         struct fbuf_t *loc_src_primary = NULL, *p_read;
771         int i;
772         /* if no device was found in the config file */
773         if (!env->out.device_num)
774                 return NULL;
775         /* every time this function is called we refresh the buffers of every device,
776         updating the private device buffer in the device table */
777         for (i = 0; i < env->out.device_num; i++) {
778                 p_read = grabber_read(&env->out.devices[i], env->out.fps);
779                 /* it is used only if different from NULL, we mantain last good buffer otherwise */
780                 if (p_read)
781                         env->out.devices[i].dev_buf = p_read;
782         }
783         /* select the primary device buffer as the one to encode */
784         loc_src_primary = env->out.devices[env->out.device_primary].dev_buf;
785         /* loc_src_primary can be NULL if the device has been turned off during
786         execution of it is read too early */
787         if (loc_src_primary) {
788                 /* Scale the video for the encoder, then use it for local rendering
789                 so we will see the same as the remote party */
790                 my_scale(loc_src_primary, NULL, &env->enc_in, NULL);
791         }
792         if (env->out.picture_in_picture) { /* the picture in picture mode is enabled */
793                 struct fbuf_t *loc_src_secondary;
794                 /* reads from the secondary source */
795                 loc_src_secondary = env->out.devices[env->out.device_secondary].dev_buf;
796                 if (loc_src_secondary) {
797                         env->enc_in.win_x = env->out.pip_x;
798                         env->enc_in.win_y = env->out.pip_y;
799                         env->enc_in.win_w = env->enc_in.w/3;
800                         env->enc_in.win_h = env->enc_in.h/3;
801                         /* scales to the correct geometry and inserts in
802                         the enc_in buffer the picture in picture */
803                         my_scale(loc_src_secondary, NULL, &env->enc_in, NULL);
804                         /* returns to normal parameters (not picture in picture) */
805                         env->enc_in.win_x = 0;
806                         env->enc_in.win_y = 0;
807                         env->enc_in.win_w = 0;
808                         env->enc_in.win_h = 0;
809                 }
810                 else {
811                         /* loc_src_secondary can be NULL if the device has been turned off during
812                         execution of it is read too early */
813                         env->out.picture_in_picture = 0; /* disable picture in picture */
814                 }
815         }
816         show_frame(env, WIN_LOCAL); /* local rendering */
817         for (i = 0; i < env->out.device_num; i++) 
818                 show_frame(env, i+WIN_SRC1); /* rendering of every source device in thumbnails */
819         if (tail == NULL)
820                 tail = &dummy;
821         *tail = NULL;
822         /* if no reason for encoding, do not encode */
823         if (!env->owner || !loc_src_primary || !v->sendvideo)
824                 return NULL;
825         if (v->enc_out.data == NULL) {
826                 static volatile int a = 0;
827                 if (a++ < 2)
828                         ast_log(LOG_WARNING, "fail, no encoder output buffer\n");
829                 return NULL;
830         }
831         v->enc->enc_run(v);
832         return v->enc->enc_encap(&v->enc_out, v->mtu, tail);
833 }
834
835 /*
836  * Helper thread to periodically poll the video sources and enqueue the
837  * generated frames directed to the remote party to the channel's queue.
838  * Using a separate thread also helps because the encoding can be
839  * computationally expensive so we don't want to starve the main thread.
840  */
841 static void *video_thread(void *arg)
842 {
843         struct video_desc *env = arg;
844         int count = 0;
845         char save_display[128] = "";
846         int i; /* integer variable used as iterator */
847
848         /* if sdl_videodriver is set, override the environment. Also,
849          * if it contains 'console' override DISPLAY around the call to SDL_Init
850          * so we use the console as opposed to the x11 version of aalib
851          */
852         if (!ast_strlen_zero(env->sdl_videodriver)) { /* override */
853                 const char *s = getenv("DISPLAY");
854                 setenv("SDL_VIDEODRIVER", env->sdl_videodriver, 1);
855                 if (s && !strcasecmp(env->sdl_videodriver, "aalib-console")) {
856                         ast_copy_string(save_display, s, sizeof(save_display));
857                         unsetenv("DISPLAY");
858                 }
859         }
860         sdl_setup(env);
861         if (!ast_strlen_zero(save_display))
862                 setenv("DISPLAY", save_display, 1);
863
864         ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */
865
866         if (grabber_open(&env->out)) {
867                 ast_log(LOG_WARNING, "cannot open local video source\n");
868         } 
869
870         if (env->out.device_num)
871                 env->out.devices[env->out.device_primary].status_index |= IS_PRIMARY | IS_SECONDARY;
872         
873         /* even if no device is connected, we must call video_out_init,
874          * as some of the data structures it initializes are
875          * used in get_video_frames()
876          */
877         video_out_init(env);
878
879         /* Writes intial status of the sources. */
880         for (i = 0; i < env->out.device_num; i++) {
881                 print_message(env->gui->thumb_bd_array[i].board,
882                  src_msgs[env->out.devices[i].status_index]);
883         }
884
885         for (;;) {
886                 struct timeval t = { 0, 50000 };        /* XXX 20 times/sec */
887                 struct ast_frame *p, *f;
888                 struct ast_channel *chan;
889                 int fd;
890                 char *caption = NULL, buf[160];
891
892                 /* determine if video format changed */
893                 if (count++ % 10 == 0) {
894                         if (env->out.sendvideo && env->out.devices)
895                             sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
896                                 env->out.devices[env->out.device_primary].name, env->codec_name,
897                                 env->enc_in.w, env->enc_in.h,
898                                 env->out.fps, env->out.bitrate/1000);
899                         else
900                             sprintf(buf, "hold");
901                         caption = buf;
902                 }
903
904                 /* manage keypad events */
905                 /* XXX here we should always check for events,
906                 * otherwise the drag will not work */ 
907                 if (env->gui)
908                         eventhandler(env, caption);
909  
910                 /* sleep for a while */
911                 ast_select(0, NULL, NULL, NULL, &t);
912
913             if (env->in) {
914                 struct video_dec_desc *v = env->in;
915                 
916                 /*
917                  * While there is something to display, call the decoder and free
918                  * the buffer, possibly enabling the receiver to store new data.
919                  */
920                 while (v->dec_in_dpy) {
921                         struct fbuf_t *tmp = v->dec_in_dpy;     /* store current pointer */
922
923                         if (v->d_callbacks->dec_run(v, tmp))
924                                 show_frame(env, WIN_REMOTE);
925                         tmp->used = 0;  /* mark buffer as free */
926                         tmp->ebit = 0;
927                         ast_mutex_lock(&env->dec_lock);
928                         if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN])    /* advance to next, circular */
929                                 v->dec_in_dpy = &v->dec_in[0];
930
931                         if (v->dec_in_cur == NULL)      /* receiver was idle, enable it... */
932                                 v->dec_in_cur = tmp;    /* using the slot just freed */
933                         else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
934                                 v->dec_in_dpy = NULL;   /* nothing more to display */
935                         ast_mutex_unlock(&env->dec_lock);
936                 }
937             }
938
939                 if (env->shutdown)
940                         break;
941                 f = get_video_frames(env, &p);  /* read and display */
942                 if (!f)
943                         continue;
944                 chan = env->owner;
945                 if (chan == NULL) {
946                         /* drop the chain of frames, nobody uses them */
947                         while (f) {
948                                 struct ast_frame *g = AST_LIST_NEXT(f, frame_list);
949                                 ast_frfree(f);
950                                 f = g;
951                         }
952                         continue;
953                 }
954                 fd = chan->alertpipe[1];
955                 ast_channel_lock(chan);
956
957                 /* AST_LIST_INSERT_TAIL is only good for one frame, cannot use here */
958                 if (chan->readq.first == NULL) {
959                         chan->readq.first = f;
960                 } else {
961                         chan->readq.last->frame_list.next = f;
962                 }
963                 chan->readq.last = p;
964                 /*
965                  * more or less same as ast_queue_frame, but extra
966                  * write on the alertpipe to signal frames.
967                  */
968                 if (fd > -1) {
969                         int blah = 1, l = sizeof(blah);
970                         for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
971                                 if (write(fd, &blah, l) != l)
972                                         ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
973                                             chan->name, f->frametype, f->subclass, strerror(errno));
974                         }
975                 }
976                 ast_channel_unlock(chan);
977         }
978         /* thread terminating, here could call the uninit */
979         /* uninitialize the local and remote video environments */
980         env->in = dec_uninit(env->in);
981         video_out_uninit(env);
982
983         if (env->gui)
984                 env->gui = cleanup_sdl(env->gui, env->out.device_num);
985         ast_mutex_destroy(&env->dec_lock);
986         env->shutdown = 0;
987         return NULL;
988 }
989
990 static void copy_geometry(struct fbuf_t *src, struct fbuf_t *dst)
991 {
992         if (dst->w == 0)
993                 dst->w = src->w;
994         if (dst->h == 0)
995                 dst->h = src->h;
996 }
997
998 /*! initialize the video environment.
999  * Apart from the formats (constant) used by sdl and the codec,
1000  * we use enc_in as the basic geometry.
1001  */
1002 static void init_env(struct video_desc *env)
1003 {
1004         struct fbuf_t *c = &(env->out.loc_src_geometry);                /* local source */
1005         struct fbuf_t *ei = &(env->enc_in);             /* encoder input */
1006         struct fbuf_t *ld = &(env->loc_dpy);    /* local display */
1007         struct fbuf_t *rd = &(env->rem_dpy);            /* remote display */
1008         int i; /* integer working as iterator */
1009
1010         c->pix_fmt = PIX_FMT_YUV420P;   /* default - camera format */
1011         ei->pix_fmt = PIX_FMT_YUV420P;  /* encoder input */
1012         if (ei->w == 0 || ei->h == 0) {
1013                 ei->w = 352;
1014                 ei->h = 288;
1015         }
1016         ld->pix_fmt = rd->pix_fmt = PIX_FMT_YUV420P; /* sdl format */
1017         /* inherit defaults */
1018         copy_geometry(ei, c);   /* camera inherits from encoder input */
1019         copy_geometry(ei, rd);  /* remote display inherits from encoder input */
1020         copy_geometry(rd, ld);  /* local display inherits from remote display */
1021
1022         /* fix the size of buffers for small windows */
1023         for (i = 0; i < env->out.device_num; i++) {
1024                 env->src_dpy[i].pix_fmt = PIX_FMT_YUV420P;
1025                 env->src_dpy[i].w = SRC_WIN_W;
1026                 env->src_dpy[i].h = SRC_WIN_H;
1027         }
1028         /* now we set the default coordinates for the picture in picture
1029         frames inside the env_in buffers, those can be changed by dragging the
1030         picture in picture with left click */
1031         env->out.pip_x = ei->w - ei->w/3;
1032         env->out.pip_y = ei->h - ei->h/3;
1033 }
1034
1035 /*!
1036  * The first call to the video code, called by oss_new() or similar.
1037  * Here we initialize the various components we use, namely SDL for display,
1038  * ffmpeg for encoding/decoding, and a local video source.
1039  * We do our best to progress even if some of the components are not
1040  * available.
1041  */
1042 void console_video_start(struct video_desc *env, struct ast_channel *owner)
1043 {
1044         ast_log(LOG_WARNING, "env %p chan %p\n", env, owner);
1045         if (env == NULL)        /* video not initialized */
1046                 return;
1047         env->owner = owner;     /* work even if no owner is specified */
1048         if (env->stayopen)
1049                 return;         /* already initialized, nothing to do */
1050         init_env(env);
1051         env->out.enc = map_config_video_format(env->codec_name);
1052
1053         ast_log(LOG_WARNING, "start video out %s %dx%d\n",
1054                 env->codec_name, env->enc_in.w,  env->enc_in.h);
1055         /*
1056          * Register all codecs supported by the ffmpeg library.
1057          * We only need to do it once, but probably doesn't
1058          * harm to do it multiple times.
1059          */
1060         avcodec_init();
1061         avcodec_register_all();
1062         av_log_set_level(AV_LOG_ERROR); /* only report errors */
1063
1064         if (env->out.fps == 0) {
1065                 env->out.fps = 15;
1066                 ast_log(LOG_WARNING, "fps unset, forcing to %d\n", env->out.fps);
1067         }
1068         if (env->out.bitrate == 0) {
1069                 env->out.bitrate = 65000;
1070                 ast_log(LOG_WARNING, "bitrate unset, forcing to %d\n", env->out.bitrate);
1071         }
1072         /* XXX below probably can use ast_pthread_create_detace\hed() */
1073         ast_pthread_create_background(&env->vthread, NULL, video_thread, env);
1074         /* detach the thread to make sure memory is freed on termination */
1075         pthread_detach(env->vthread);
1076         if (env->owner == NULL)
1077                 env->stayopen = 1;      /* manually opened so don't close on hangup */
1078 }
1079
1080 /*
1081  * Parse a geometry string, accepting also common names for the formats.
1082  * Trick: if we have a leading > or < and a numeric geometry,
1083  * return the larger or smaller one.
1084  * E.g. <352x288 gives the smaller one, 320x240
1085  */
1086 static int video_geom(struct fbuf_t *b, const char *s)
1087 {
1088         int w = 0, h = 0;
1089
1090         static struct {
1091                 const char *s; int w; int h;
1092         } *fp, formats[] = {
1093                 {"16cif",       1408, 1152 },
1094                 {"xga",         1024, 768 },
1095                 {"4cif",        704, 576 },
1096                 {"vga",         640, 480 },
1097                 {"cif",         352, 288 },
1098                 {"qvga",        320, 240 },
1099                 {"qcif",        176, 144 },
1100                 {"sqcif",       128, 96 },
1101                 {NULL,          0, 0 },
1102         };
1103         if (*s == '<' || *s == '>')
1104                 sscanf(s+1,"%dx%d", &w, &h);
1105         for (fp = formats; fp->s; fp++) {
1106                 if (*s == '>') {        /* look for a larger one */
1107                         if (fp->w <= w) {
1108                                 if (fp > formats)
1109                                         fp--; /* back one step if possible */
1110                                 break;
1111                         }
1112                 } else if (*s == '<') { /* look for a smaller one */
1113                         if (fp->w < w)
1114                                 break;
1115                 } else if (!strcasecmp(s, fp->s)) { /* look for a string */
1116                         break;
1117                 }
1118         }
1119         if (*s == '<' && fp->s == NULL) /* smallest */
1120                 fp--;
1121         if (fp->s) {
1122                 b->w = fp->w;
1123                 b->h = fp->h;
1124         } else if (sscanf(s, "%dx%d", &b->w, &b->h) != 2) {
1125                 ast_log(LOG_WARNING, "Invalid video_size %s, using 352x288\n", s);
1126                 b->w = 352;
1127                 b->h = 288;
1128         }
1129         return 0;
1130 }
1131
1132
1133 /*! \brief add an entry to the video_device table,
1134  * ignoring duplicate names.
1135  * The table is a static array of 9 elements.
1136  * The last_frame field of each entry of the table is initialized to
1137  * the current time (we need a value inside this field, on stop of the
1138  * GUI the last_frame value is not changed, to avoid checking if it is 0 we
1139  * set the initial value on current time) XXX
1140  *
1141  * PARAMETERS:
1142  * \param devices_p = pointer to the table of devices
1143  * \param device_num_p = pointer to the number of devices
1144  * \param s = name of the new device to insert
1145  *
1146  * returns 0 on success, 1 on error
1147  */
1148 static int device_table_fill(struct video_device *devices, int *device_num_p, const char *s)
1149 {
1150         int i;
1151         struct video_device *p;
1152
1153         /* with the current implementation, we support a maximum of 9 devices.*/
1154         if (*device_num_p >= 9)
1155                 return 0; /* more devices will be ignored */
1156         /* ignore duplicate names */
1157         for (i = 0; i < *device_num_p; i++) {
1158                 if (!strcmp(devices[i].name, s))
1159                         return 0;
1160         }
1161         /* inserts the new video device */
1162         p = &devices[*device_num_p];
1163         /* XXX the string is allocated but NEVER deallocated,
1164         the good time to do that is when the module is unloaded, now we skip the problem */
1165         p->name = ast_strdup(s);                /* copy the name */
1166         /* other fields initially NULL */
1167         p->grabber = NULL;
1168         p->grabber_data = NULL;
1169         p->dev_buf = NULL;
1170         p->last_frame = ast_tvnow();
1171         p->status_index = 0;
1172         (*device_num_p)++;                      /* one device added */
1173         return 0;
1174 }
1175
1176 /* extend ast_cli with video commands. Called by console_video_config */
1177 int console_video_cli(struct video_desc *env, const char *var, int fd)
1178 {
1179         if (env == NULL)
1180                 return 1;       /* unrecognised */
1181
1182         if (!strcasecmp(var, "videodevice")) {
1183                 ast_cli(fd, "videodevice is [%s]\n", env->out.devices[env->out.device_primary].name);
1184         } else if (!strcasecmp(var, "videocodec")) {
1185                 ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
1186         } else if (!strcasecmp(var, "sendvideo")) {
1187                 ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
1188         } else if (!strcasecmp(var, "video_size")) {
1189                 int in_w = 0, in_h = 0;
1190                 if (env->in) {
1191                         in_w = env->in->dec_out.w;
1192                         in_h = env->in->dec_out.h;
1193                 }
1194                 ast_cli(fd, "sizes: video %dx%d camera %dx%d local %dx%d remote %dx%d in %dx%d\n",
1195                         env->enc_in.w, env->enc_in.h,
1196                         env->out.loc_src_geometry.w, env->out.loc_src_geometry.h,
1197                         env->loc_dpy.w, env->loc_dpy.h,
1198                         env->rem_dpy.w, env->rem_dpy.h,
1199                         in_w, in_h);
1200         } else if (!strcasecmp(var, "bitrate")) {
1201                 ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
1202         } else if (!strcasecmp(var, "qmin")) {
1203                 ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
1204         } else if (!strcasecmp(var, "fps")) {
1205                 ast_cli(fd, "fps is [%d]\n", env->out.fps);
1206         } else if (!strcasecmp(var, "startgui")) {
1207                 console_video_start(env, NULL);
1208         } else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
1209                 env->stayopen = 0;
1210                 if (env->gui && env->owner)
1211                         ast_cli_command(-1, "console hangup");
1212                 else /* not in a call */
1213                         console_video_uninit(env);
1214         } else {
1215                 return 1;       /* unrecognised */
1216         }
1217         return 0;       /* recognised */
1218 }
1219
1220 /*! parse config command for video support. */
1221 int console_video_config(struct video_desc **penv,
1222         const char *var, const char *val)
1223 {
1224         struct video_desc *env;
1225
1226         if (penv == NULL) {
1227                 ast_log(LOG_WARNING, "bad argument penv=NULL\n");
1228                 return 1;       /* error */
1229         }
1230         /* allocate the video descriptor first time we get here */
1231         env = *penv;
1232         if (env == NULL) {
1233                 env = *penv = ast_calloc(1, sizeof(struct video_desc));
1234                 if (env == NULL) {
1235                         ast_log(LOG_WARNING, "fail to allocate video_desc\n");
1236                         return 1;       /* error */
1237                 
1238                 }
1239                 /* set default values */
1240                 env->out.device_primary = 0;
1241                 env->out.device_secondary = 0;
1242                 env->out.fps = 5;
1243                 env->out.bitrate = 65000;
1244                 env->out.sendvideo = 1;
1245                 env->out.qmin = 3;
1246                 env->out.device_num = 0;
1247                 env->out.picture_in_picture = 0; /* PiP mode intially disabled */
1248         }
1249         CV_START(var, val);
1250         CV_F("videodevice", device_table_fill(env->out.devices, &env->out.device_num, val));
1251         CV_BOOL("sendvideo", env->out.sendvideo);
1252         CV_F("video_size", video_geom(&env->enc_in, val));
1253         CV_F("camera_size", video_geom(&env->out.loc_src_geometry, val));
1254         CV_F("local_size", video_geom(&env->loc_dpy, val));
1255         CV_F("remote_size", video_geom(&env->rem_dpy, val));
1256         CV_STR("keypad", env->keypad_file);
1257         CV_F("region", keypad_cfg_read(env->gui, val));
1258         CV_F("startgui", console_video_start(env, NULL));       // support enabling gui at startup
1259         CV_STR("keypad_font", env->keypad_font);
1260         CV_STR("sdl_videodriver", env->sdl_videodriver);
1261         CV_UINT("fps", env->out.fps);
1262         CV_UINT("bitrate", env->out.bitrate);
1263         CV_UINT("qmin", env->out.qmin);
1264         CV_STR("videocodec", env->codec_name);
1265         return 1;       /* nothing found */
1266
1267         CV_END;         /* the 'nothing found' case */
1268         return 0;               /* found something */
1269 }
1270
1271 #endif  /* video support */