fix a small bug in printing out geometries - wrong input.
[asterisk/asterisk.git] / channels / console_video.c
1 /*
2  * Experimental support for video sessions. We use SDL for rendering, ffmpeg
3  * as the codec library for encoding and decoding, and Video4Linux and X11
4  * to generate the local video stream.
5  *
6  * If one of these pieces is not available, either at compile time or at
7  * runtime, we do our best to run without it. Of course, no codec library
8  * means we can only deal with raw data, no SDL means we cannot do rendering,
9  * no V4L or X11 means we cannot generate data (but in principle we could
10  * stream from or record to a file).
11  *
12  * We need a recent (2007.07.12 or newer) version of ffmpeg to avoid warnings.
13  * Older versions might give 'deprecated' messages during compilation,
14  * thus not compiling in AST_DEVMODE, or don't have swscale, in which case
15  * you can try to compile #defining OLD_FFMPEG here.
16  *
17  * $Revision$
18  */
19
20 //#define DROP_PACKETS 5       /* if set, drop this % of video packets */
21 //#define OLD_FFMPEG    1       /* set for old ffmpeg with no swscale */
22
23 #include "asterisk.h"
24 #include <sys/ioctl.h>
25 #include "asterisk/cli.h"
26 #include "asterisk/file.h"
27 #include "asterisk/channel.h"
28
29 #include "console_video.h"
30
31 /*
32 The code is structured as follows.
33
34 When a new console channel is created, we call console_video_start()
35 to initialize SDL, the source, and the encoder/ decoder for the
36 formats in use (XXX the latter two should be done later, once the
37 codec negotiation is complete).  Also, a thread is created to handle
38 the video source and generate frames.
39
40 While communication is on, the local source is generated by the
41 video thread, which wakes up periodically, generates frames and
42 enqueues them in chan->readq.  Incoming rtp frames are passed to
43 console_write_video(), decoded and passed to SDL for display.
44
45 For as unfortunate and confusing as it can be, we need to deal with a
46 number of different video representations (size, codec/pixel format,
47 codec parameters), as follows:
48
49  loc_src        is the data coming from the camera/X11/etc.
50         The format is typically constrained by the video source.
51
52  enc_in         is the input required by the encoder.
53         Typically constrained in size by the encoder type.
54
55  enc_out        is the bitstream transmitted over RTP.
56         Typically negotiated while the call is established.
57
58  loc_dpy        is the format used to display the local video source.
59         Depending on user preferences this can have the same size as
60         loc_src_fmt, or enc_in_fmt, or thumbnail size (e.g. PiP output)
61
62  dec_in         is the incoming RTP bitstream. Negotiated
63         during call establishment, it is not necessarily the same as
64         enc_in_fmt
65
66  dec_out        the output of the decoder.
67         The format is whatever the other side sends, and the
68         buffer is allocated by avcodec_decode_... so we only
69         copy the data here.
70
71  rem_dpy        the format used to display the remote stream
72
73 We store the format info together with the buffer storing the data.
74 As a future optimization, a format/buffer may reference another one
75 if the formats are equivalent. This will save some unnecessary format
76 conversion.
77
78
79 In order to handle video you need to add to sip.conf (and presumably
80 iax.conf too) the following:
81
82         [general](+)
83                 videosupport=yes
84                 allow=h263      ; this or other video formats
85                 allow=h263p     ; this or other video formats
86
87  */
88
89 /*
90  * Codecs are absolutely necessary or we cannot do anything.
91  * SDL is optional (used for rendering only), so that we can still
92  * stream video withouth displaying it.
93  */
94 #if !defined(HAVE_VIDEO_CONSOLE) || !defined(HAVE_FFMPEG)
95 /* stubs if required pieces are missing */
96 int console_write_video(struct ast_channel *chan, struct ast_frame *f)
97 {
98         return 0;       /* writing video not supported */
99 }
100
101 int console_video_cli(struct video_desc *env, const char *var, int fd)
102 {
103         return 1;       /* nothing matched */
104 }
105
106 int console_video_config(struct video_desc **penv, const char *var, const char *val)
107 {
108         return 1;       /* no configuration */
109 }
110
111 void console_video_start(struct video_desc *env, struct ast_channel *owner)
112 {
113         ast_log(LOG_NOTICE, "voice only, console video support not present\n");
114 }
115
116 void console_video_uninit(struct video_desc *env)
117 {
118 }
119
120 int console_video_formats = 0;
121
122 #else /* defined(HAVE_FFMPEG) && defined(HAVE_SDL) */
123
124 /*! The list of video formats we support. */
125 int console_video_formats = 
126         AST_FORMAT_H263_PLUS | AST_FORMAT_H263 |
127         AST_FORMAT_MP4_VIDEO | AST_FORMAT_H264 | AST_FORMAT_H261 ;
128
129
130 /*
131  * In many places we use buffers to store the raw frames (but not only),
132  * so here is a structure to keep all the info. data = NULL means the
133  * structure is not initialized, so the other fields are invalid.
134  * size = 0 means the buffer is not malloc'ed so we don't have to free it.
135  */
136 struct fbuf_t {         /* frame buffers, dynamically allocated */
137         uint8_t *data;  /* memory, malloced if size > 0, just reference
138                          * otherwise */
139         int     size;   /* total size in bytes */
140         int     used;   /* space used so far */
141         int     ebit;   /* bits to ignore at the end */
142         int     x;      /* origin, if necessary */
143         int     y;
144         int     w;      /* size */ 
145         int     h;
146         int     pix_fmt;
147 };
148
149 static void my_scale(struct fbuf_t *in, AVPicture *p_in,
150         struct fbuf_t *out, AVPicture *p_out);
151
152 struct video_codec_desc;        /* forward declaration */
153 /*
154  * Descriptor of the local source, made of the following pieces:
155  *  + configuration info (geometry, device name, fps...). These are read
156  *    from the config file and copied here before calling video_out_init();
157  *  + the frame buffer (buf) and source pixel format, allocated at init time;
158  *  + the encoding and RTP info, including timestamps to generate
159  *    frames at the correct rate;
160  *  + source-specific info, i.e. fd for /dev/video, dpy-image for x11, etc,
161  *    filled in by video_open
162  * NOTE: loc_src.data == NULL means the rest of the struct is invalid, and
163  *      the video source is not available.
164  */
165 struct video_out_desc {
166         /* video device support.
167          * videodevice and geometry are read from the config file.
168          * At the right time we try to open it and allocate a buffer.
169          * If we are successful, webcam_bufsize > 0 and we can read.
170          */
171         /* all the following is config file info copied from the parent */
172         char            videodevice[64];
173         int             fps;
174         int             bitrate;
175         int             qmin;
176
177         int sendvideo;
178
179         struct fbuf_t   loc_src;        /* local source buffer, allocated in video_open() */
180         struct fbuf_t   enc_in;         /* encoder input buffer, allocated in video_out_init() */
181         struct fbuf_t   enc_out;        /* encoder output buffer, allocated in video_out_init() */
182         struct fbuf_t   loc_dpy;        /* display source buffer, no buffer (managed by SDL in bmp[1]) */
183
184         struct video_codec_desc *enc;   /* encoder */
185         void            *enc_ctx;       /* encoding context */
186         AVCodec         *codec;
187         AVFrame         *enc_in_frame;  /* enc_in mapped into avcodec format. */
188                                         /* The initial part of AVFrame is an AVPicture */
189         int             mtu;
190         struct timeval  last_frame;     /* when we read the last frame ? */
191
192         /* device specific info */
193         int             fd;             /* file descriptor, for webcam */
194 #ifdef HAVE_X11
195         Display         *dpy;                   /* x11 grabber info */
196         XImage          *image;
197         int             screen_width;   /* width of X screen */
198         int             screen_height;  /* height of X screen */
199 #endif
200 };
201
202 /*
203  * Descriptor for the incoming stream, with a buffer for the bitstream
204  * extracted by the RTP packets, RTP reassembly info, and a frame buffer
205  * for the decoded frame (buf).
206  * and store the result in a suitable frame buffer for later display.
207  * NOTE: dec_ctx == NULL means the rest is invalid (e.g. because no
208  *      codec, no memory, etc.) and we must drop all incoming frames.
209  *
210  * Incoming payload is stored in one of the dec_in[] buffers, which are
211  * emptied by the video thread. These buffers are organized in a circular
212  * queue, with dec_in_cur being the buffer in use by the incoming stream,
213  * and dec_in_dpy is the one being displayed. When the pointers need to
214  * be changed, we synchronize the access to them with dec_in_lock.
215  * When the list is full dec_in_cur = NULL (we cannot store new data),
216  * when the list is empty dec_in_dpy is NULL (we cannot display frames).
217  */
218 struct video_in_desc {
219         struct video_codec_desc *dec;   /* decoder */
220         AVCodecContext          *dec_ctx;       /* information about the codec in the stream */
221         AVCodec                 *codec;         /* reference to the codec */
222         AVFrame                 *d_frame;       /* place to store the decoded frame */
223         AVCodecParserContext    *parser;
224         uint16_t                next_seq;       /* must be 16 bit */
225         int                     discard;        /* flag for discard status */
226 #define N_DEC_IN        3       /* number of incoming buffers */
227         struct fbuf_t           *dec_in_cur;    /* buffer being filled in */
228         struct fbuf_t           *dec_in_dpy;    /* buffer to display */
229         ast_mutex_t             dec_in_lock;
230         struct fbuf_t dec_in[N_DEC_IN]; /* incoming bitstream, allocated/extended in fbuf_append() */
231         struct fbuf_t dec_out;  /* decoded frame, no buffer (data is in AVFrame) */
232         struct fbuf_t rem_dpy;  /* display remote image, no buffer (it is in win[WIN_REMOTE].bmp) */
233 };
234
235
236 /*
237  * The overall descriptor, with room for config info, video source and
238  * received data descriptors, SDL info, etc.
239  */
240 struct video_desc {
241         char                    codec_name[64]; /* the codec we use */
242
243         pthread_t               vthread;        /* video thread */
244         int                     shutdown;       /* set to shutdown vthread */
245         struct ast_channel      *owner;         /* owner channel */
246
247         struct video_in_desc    in;             /* remote video descriptor */
248         struct video_out_desc   out;            /* local video descriptor */
249
250         struct gui_info         *gui;
251
252         char                    keypad_file[256];       /* image for the keypad */
253         char                    keypad_font[256];       /* font for the keypad */
254
255         char                    sdl_videodriver[256];
256 };
257
258 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
259
260 static void fbuf_free(struct fbuf_t *b)
261 {
262         struct fbuf_t x = *b;
263
264         if (b->data && b->size)
265                 ast_free(b->data);
266         bzero(b, sizeof(*b));
267         /* restore some fields */
268         b->w = x.w;
269         b->h = x.h;
270         b->pix_fmt = x.pix_fmt;
271 }
272
273 /*
274  * Append a chunk of data to a buffer taking care of bit alignment
275  * Return 0 on success, != 0 on failure
276  */
277 static int fbuf_append(struct fbuf_t *b, uint8_t *src, int len,
278         int sbit, int ebit)
279 {
280         /*
281          * Allocate buffer. ffmpeg wants an extra FF_INPUT_BUFFER_PADDING_SIZE,
282          * and also wants 0 as a buffer terminator to prevent trouble.
283          */
284         int need = len + FF_INPUT_BUFFER_PADDING_SIZE;
285         int i;
286         uint8_t *dst, mask;
287
288         if (b->data == NULL) {
289                 b->size = need;
290                 b->used = 0;
291                 b->ebit = 0;
292                 b->data = ast_calloc(1, b->size);
293         } else if (b->used + need > b->size) {
294                 b->size = b->used + need;
295                 b->data = ast_realloc(b->data, b->size);
296         }
297         if (b->data == NULL) {
298                 ast_log(LOG_WARNING, "alloc failure for %d, discard\n",
299                         b->size);
300                 return 1;
301         }
302         if (b->used == 0 && b->ebit != 0) {
303                 ast_log(LOG_WARNING, "ebit not reset at start\n");
304                 b->ebit = 0;
305         }
306         dst = b->data + b->used;
307         i = b->ebit + sbit;     /* bits to ignore around */
308         if (i == 0) {   /* easy case, just append */
309                 /* do everything in the common block */
310         } else if (i == 8) { /* easy too, just handle the overlap byte */
311                 mask = (1 << b->ebit) - 1;
312                 /* update the last byte in the buffer */
313                 dst[-1] &= ~mask;       /* clear bits to ignore */
314                 dst[-1] |= (*src & mask);       /* append new bits */
315                 src += 1;       /* skip and prepare for common block */
316                 len --;
317         } else {        /* must shift the new block, not done yet */
318                 ast_log(LOG_WARNING, "must handle shift %d %d at %d\n",
319                         b->ebit, sbit, b->used);
320                 return 1;
321         }
322         memcpy(dst, src, len);
323         b->used += len;
324         b->ebit = ebit;
325         b->data[b->used] = 0;   /* padding */
326         return 0;
327 }
328
329 /*!
330  * Build an ast_frame for a given chunk of data, and link it into
331  * the queue, with possibly 'head' bytes at the beginning to
332  * fill in some fields later.
333  */
334 static struct ast_frame *create_video_frame(uint8_t *start, uint8_t *end,
335                        int format, int head, struct ast_frame *prev)
336 {
337         int len = end-start;
338         uint8_t *data;
339         struct ast_frame *f;
340
341         data = ast_calloc(1, len+head);
342         f = ast_calloc(1, sizeof(*f));
343         if (f == NULL || data == NULL) {
344                 ast_log(LOG_WARNING, "--- frame error f %p data %p len %d format %d\n",
345                                 f, data, len, format);
346                 if (f)
347                         ast_free(f);
348                 if (data)
349                         ast_free(data);
350                 return NULL;
351         }
352         memcpy(data+head, start, len);
353         f->data = data;
354         f->mallocd = AST_MALLOCD_DATA | AST_MALLOCD_HDR;
355         //f->has_timing_info = 1;
356         //f->ts = ast_tvdiff_ms(ast_tvnow(), out->ts);
357         f->datalen = len+head;
358         f->frametype = AST_FRAME_VIDEO;
359         f->subclass = format;
360         f->samples = 0;
361         f->offset = 0;
362         f->src = "Console";
363         f->delivery.tv_sec = 0;
364         f->delivery.tv_usec = 0;
365         f->seqno = 0;
366         AST_LIST_NEXT(f, frame_list) = NULL;
367
368         if (prev)
369                 AST_LIST_NEXT(prev, frame_list) = f;
370
371         return f;
372 }
373
374 #include "vcodecs.c"
375 #include "console_gui.c"
376
377 /*------ end codec specific code -----*/
378
379
380 /* Video4Linux stuff is only used in video_open() */
381 #ifdef HAVE_VIDEODEV_H
382 #include <linux/videodev.h>
383 #endif
384
385 /*!
386  * Open the local video source and allocate a buffer
387  * for storing the image. Return 0 on success, -1 on error
388  */
389 static int video_open(struct video_out_desc *v)
390 {
391         struct fbuf_t *b = &v->loc_src;
392         if (b->data)    /* buffer allocated means device already open */
393                 return v->fd;
394         v->fd = -1;
395         /*
396          * if the device is "X11", then open the x11 grabber
397          */
398     if (!strcasecmp(v->videodevice, "X11")) {
399         XImage *im;
400         int screen_num;
401
402         /* init the connection with the X server */
403         v->dpy = XOpenDisplay(NULL);
404         if (v->dpy == NULL) {
405                 ast_log(LOG_WARNING, "error opening display\n");
406                 goto error;
407         }
408
409         /* find width and height of the screen */
410         screen_num = DefaultScreen(v->dpy);
411         v->screen_width = DisplayWidth(v->dpy, screen_num);
412         v->screen_height = DisplayHeight(v->dpy, screen_num);
413
414         v->image = im = XGetImage(v->dpy,
415                 RootWindow(v->dpy, DefaultScreen(v->dpy)),
416                 b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
417         if (v->image == NULL) {
418                 ast_log(LOG_WARNING, "error creating Ximage\n");
419                 goto error;
420         }
421         switch (im->bits_per_pixel) {
422         case 32:
423                 b->pix_fmt = PIX_FMT_RGBA32;
424                 break;
425         case 16:
426                 b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
427                 break;
428         }
429
430         ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
431                 im->data,
432                 im->bits_per_pixel,
433                 b->pix_fmt,
434                 im->red_mask, im->green_mask, im->blue_mask);
435
436         /* set the pointer but not the size as this is not malloc'ed */
437         b->data = (uint8_t *)im->data;
438         v->fd = -2;
439     }
440 #ifdef HAVE_VIDEODEV_H
441     else {
442         /* V4L specific */
443         struct video_window vw = { 0 }; /* camera attributes */
444         struct video_picture vp;
445         int i;
446         const char *dev = v->videodevice;
447
448         v->fd = open(dev, O_RDONLY | O_NONBLOCK);
449         if (v->fd < 0) {
450                 ast_log(LOG_WARNING, "error opening camera %s\n", v->videodevice);
451                 return v->fd;
452         }
453
454         i = fcntl(v->fd, F_GETFL);
455         if (-1 == fcntl(v->fd, F_SETFL, i | O_NONBLOCK)) {
456                 /* non fatal, just emit a warning */
457                 ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
458                         dev, strerror(errno));
459         }
460         /* set format for the camera.
461          * In principle we could retry with a different format if the
462          * one we are asking for is not supported.
463          */
464         vw.width = v->loc_src.w;
465         vw.height = v->loc_src.h;
466         vw.flags = v->fps << 16;
467         if (ioctl(v->fd, VIDIOCSWIN, &vw) == -1) {
468                 ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
469                         dev, strerror(errno));
470                 goto error;
471         }
472         if (ioctl(v->fd, VIDIOCGPICT, &vp) == -1) {
473                 ast_log(LOG_WARNING, "error reading picture info\n");
474                 goto error;
475         }
476         ast_log(LOG_WARNING,
477                 "contrast %d bright %d colour %d hue %d white %d palette %d\n",
478                 vp.contrast, vp.brightness,
479                 vp.colour, vp.hue,
480                 vp.whiteness, vp.palette);
481         /* set the video format. Here again, we don't necessary have to
482          * fail if the required format is not supported, but try to use
483          * what the camera gives us.
484          */
485         b->pix_fmt = vp.palette;
486         vp.palette = VIDEO_PALETTE_YUV420P;
487         if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
488                 ast_log(LOG_WARNING, "error setting palette, using %d\n",
489                         b->pix_fmt);
490         } else
491                 b->pix_fmt = vp.palette;
492         /* allocate the source buffer.
493          * XXX, the code here only handles yuv411, for other formats
494          * we need to look at pix_fmt and set size accordingly
495          */
496         b->size = (b->w * b->h * 3)/2;  /* yuv411 */
497         ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
498                 dev, b->w, b->h, b->size);
499         v->loc_src.data = ast_calloc(1, b->size);
500         if (!b->data) {
501                 ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
502                         b->size);
503                 goto error;
504         }
505         ast_log(LOG_WARNING, "success opening camera\n");
506     }
507 #endif /* HAVE_VIDEODEV_H */
508
509         if (v->image == NULL && v->fd < 0)
510                 goto error;
511         b->used = 0;
512         return 0;
513
514 error:
515         ast_log(LOG_WARNING, "fd %d dpy %p img %p data %p\n",
516                 v->fd, v->dpy, v->image, v->loc_src.data);
517         /* XXX maybe XDestroy (v->image) ? */
518         if (v->dpy)
519                 XCloseDisplay(v->dpy);
520         v->dpy = NULL;
521         if (v->fd >= 0)
522                 close(v->fd);
523         v->fd = -1;
524         fbuf_free(&v->loc_src);
525         return -1;
526 }
527
528 /*! \brief complete a buffer from the local video source.
529  * Called by get_video_frames(), in turn called by the video thread.
530  */
531 static int video_read(struct video_out_desc *v)
532 {
533         struct timeval now = ast_tvnow();
534         struct fbuf_t *b = &v->loc_src;
535
536         if (b->data == NULL)    /* not initialized */
537                 return 0;
538
539         /* check if it is time to read */
540         if (ast_tvzero(v->last_frame))
541                 v->last_frame = now;
542         if (ast_tvdiff_ms(now, v->last_frame) < 1000/v->fps)
543                 return 0;       /* too early */
544         v->last_frame = now; /* XXX actually, should correct for drift */
545
546 #ifdef HAVE_X11
547         if (v->image) {
548                 /* read frame from X11 */
549                 AVPicture p;
550                 XGetSubImage(v->dpy,
551                     RootWindow(v->dpy, DefaultScreen(v->dpy)),
552                         b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
553
554                 b->data = (uint8_t *)v->image->data;
555                 fill_pict(b, &p);
556                 return p.linesize[0] * b->h;
557         }
558 #endif
559         if (v->fd < 0)                  /* no other source */
560                 return 0;
561         for (;;) {
562                 int r, l = v->loc_src.size - v->loc_src.used;
563                 r = read(v->fd, v->loc_src.data + v->loc_src.used, l);
564                 // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
565                 if (r < 0)      /* read error */
566                         return 0;
567                 if (r == 0)     /* no data */
568                         return 0;
569                 v->loc_src.used += r;
570                 if (r == l) {
571                         v->loc_src.used = 0; /* prepare for next frame */
572                         return v->loc_src.size;
573                 }
574         }
575 }
576
577 /* Helper function to process incoming video.
578  * For each incoming video call invoke ffmpeg_init() to intialize
579  * the decoding structure then incoming video frames are processed
580  * by write_video() which in turn calls pre_process_data(), to extract
581  * the bitstream; accumulates data into a buffer within video_desc. When
582  * a frame is complete (determined by the marker bit in the RTP header)
583  * call decode_video() to decoding and if it successful call show_frame()
584  * to display the frame.
585  */
586
587 /*
588  * Map the codec name to the library. If not recognised, use a default.
589  * This is useful in the output path where we decide by name, presumably.
590  */
591 static struct video_codec_desc *map_config_video_format(char *name)
592 {
593         int i;
594
595         for (i = 0; supported_codecs[i]; i++)
596                 if (!strcasecmp(name, supported_codecs[i]->name))
597                         break;
598         if (supported_codecs[i] == NULL) {
599                 ast_log(LOG_WARNING, "Cannot find codec for '%s'\n", name);
600                 i = 0;
601                 strcpy(name, supported_codecs[i]->name);
602         }
603         ast_log(LOG_WARNING, "Using codec '%s'\n", name);
604         return supported_codecs[i];
605 }
606
607 /*! \brief uninitialize the descriptor for remote video stream */
608 static int video_in_uninit(struct video_in_desc *v)
609 {
610         int i;
611
612         if (v->parser) {
613                 av_parser_close(v->parser);
614                 v->parser = NULL;
615         }
616         if (v->dec_ctx) {
617                 avcodec_close(v->dec_ctx);
618                 av_free(v->dec_ctx);
619                 v->dec_ctx = NULL;
620         }
621         if (v->d_frame) {
622                 av_free(v->d_frame);
623                 v->d_frame = NULL;
624         }
625         v->codec = NULL;        /* only a reference */
626         v->dec = NULL;          /* forget the decoder */
627         v->discard = 1;         /* start in discard mode */
628         for (i = 0; i < N_DEC_IN; i++)
629                 fbuf_free(&v->dec_in[i]);
630         fbuf_free(&v->dec_out);
631         fbuf_free(&v->rem_dpy);
632         return -1;      /* error, in case someone cares */
633 }
634
635 /*
636  * initialize ffmpeg resources used for decoding frames from the network.
637  */
638 static int video_in_init(struct video_in_desc *v, uint32_t format)
639 {
640         enum CodecID codec;
641
642         /* XXX should check that these are already set */
643         v->codec = NULL;
644         v->dec_ctx = NULL;
645         v->d_frame = NULL;
646         v->parser = NULL;
647         v->discard = 1;
648
649         codec = map_video_format(format, CM_RD);
650
651         v->codec = avcodec_find_decoder(codec);
652         if (!v->codec) {
653                 ast_log(LOG_WARNING, "Unable to find the decoder for format %d\n", codec);
654                 return video_in_uninit(v);
655         }
656         /*
657         * Initialize the codec context.
658         */
659         v->dec_ctx = avcodec_alloc_context();
660         /* XXX call dec_init() ? */
661         if (avcodec_open(v->dec_ctx, v->codec) < 0) {
662                 ast_log(LOG_WARNING, "Cannot open the codec context\n");
663                 av_free(v->dec_ctx);
664                 v->dec_ctx = NULL;
665                 return video_in_uninit(v);
666         }
667
668         v->parser = av_parser_init(codec);
669         if (!v->parser) {
670                 ast_log(LOG_WARNING, "Cannot initialize the decoder parser\n");
671                 return video_in_uninit(v);
672         }
673
674         v->d_frame = avcodec_alloc_frame();
675         if (!v->d_frame) {
676                 ast_log(LOG_WARNING, "Cannot allocate decoding video frame\n");
677                 return video_in_uninit(v);
678         }
679         return 0;       /* ok */
680 }
681
682 /*! \brief uninitialize the descriptor for local video stream */
683 static int video_out_uninit(struct video_out_desc *v)
684 {
685         /* XXX this should be a codec callback */
686         if (v->enc_ctx) {
687                 AVCodecContext *enc_ctx = (AVCodecContext *)v->enc_ctx;
688                 avcodec_close(enc_ctx);
689                 av_free(enc_ctx);
690                 v->enc_ctx = NULL;
691         }
692         if (v->enc_in_frame) {
693                 av_free(v->enc_in_frame);
694                 v->enc_in_frame = NULL;
695         }
696         v->codec = NULL;        /* only a reference */
697         
698         fbuf_free(&v->loc_src);
699         fbuf_free(&v->enc_in);
700         fbuf_free(&v->enc_out);
701         fbuf_free(&v->loc_dpy);
702         if (v->image) { /* X11 grabber */
703                 XCloseDisplay(v->dpy);
704                 v->dpy = NULL;
705                 v->image = NULL;
706         }
707         if (v->fd >= 0) {
708                 close(v->fd);
709                 v->fd = -1;
710         }
711         return -1;
712 }
713
714 /*
715  * Initialize the encoder for the local source:
716  * - AVCodecContext, AVCodec, AVFrame are used by ffmpeg for encoding;
717  * - encbuf is used to store the encoded frame (to be sent)
718  * - mtu is used to determine the max size of video fragment
719  * NOTE: we enter here with the video source already open.
720  */
721 static int video_out_init(struct video_desc *env)
722 {
723         int codec;
724         int size;
725         struct fbuf_t *enc_in;
726         struct video_out_desc *v = &env->out;
727
728         v->enc_ctx              = NULL;
729         v->codec                = NULL;
730         v->enc_in_frame         = NULL;
731         v->enc_out.data         = NULL;
732
733         if (v->loc_src.data == NULL) {
734                 ast_log(LOG_WARNING, "No local source active\n");
735                 return video_out_uninit(v);
736         }
737         codec = map_video_format(v->enc->format, CM_WR);
738         v->codec = avcodec_find_encoder(codec);
739         if (!v->codec) {
740                 ast_log(LOG_WARNING, "Cannot find the encoder for format %d\n",
741                         codec);
742                 return video_out_uninit(v);
743         }
744
745         v->mtu = 1400;  /* set it early so the encoder can use it */
746
747         /* allocate the input buffer for encoding.
748          * ffmpeg only supports PIX_FMT_YUV420P for the encoding.
749          */
750         enc_in = &v->enc_in;
751         enc_in->pix_fmt = PIX_FMT_YUV420P;
752         enc_in->size = (enc_in->w * enc_in->h * 3)/2;
753         enc_in->data = ast_calloc(1, enc_in->size);
754         if (!enc_in->data) {
755                 ast_log(LOG_WARNING, "Cannot allocate encoder input buffer\n");
756                 return video_out_uninit(v);
757         }
758         /* construct an AVFrame that points into buf_in */
759         v->enc_in_frame = avcodec_alloc_frame();
760         if (!v->enc_in_frame) {
761                 ast_log(LOG_WARNING, "Unable to allocate the encoding video frame\n");
762                 return video_out_uninit(v);
763         }
764
765         /* parameters for PIX_FMT_YUV420P */
766         size = enc_in->w * enc_in->h;
767         v->enc_in_frame->data[0] = enc_in->data;
768         v->enc_in_frame->data[1] = v->enc_in_frame->data[0] + size;
769         v->enc_in_frame->data[2] = v->enc_in_frame->data[1] + size/4;
770         v->enc_in_frame->linesize[0] = enc_in->w;
771         v->enc_in_frame->linesize[1] = enc_in->w/2;
772         v->enc_in_frame->linesize[2] = enc_in->w/2;
773
774         /* now setup the parameters for the encoder.
775          * XXX should be codec-specific
776          */
777     {
778         AVCodecContext *enc_ctx = avcodec_alloc_context();
779         v->enc_ctx = enc_ctx;
780         enc_ctx->pix_fmt = enc_in->pix_fmt;
781         enc_ctx->width = enc_in->w;
782         enc_ctx->height = enc_in->h;
783         /* XXX rtp_callback ?
784          * rtp_mode so ffmpeg inserts as many start codes as possible.
785          */
786         enc_ctx->rtp_mode = 1;
787         enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
788         enc_ctx->bit_rate = v->bitrate;
789         enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
790         enc_ctx->qmin = v->qmin;        /* should be configured */
791         enc_ctx->time_base = (AVRational){1, v->fps};
792         enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
793
794         v->enc->enc_init(v->enc_ctx);
795  
796         if (avcodec_open(enc_ctx, v->codec) < 0) {
797                 ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
798                         codec);
799                 av_free(enc_ctx);
800                 v->enc_ctx = NULL;
801                 return video_out_uninit(v);
802         }
803     }
804         /*
805          * Allocate enough for the encoded bitstream. As we are compressing,
806          * we hope that the output is never larger than the input size.
807          */
808         v->enc_out.data = ast_calloc(1, enc_in->size);
809         v->enc_out.size = enc_in->size;
810         v->enc_out.used = 0;
811
812         return 0;
813 }
814
815 /*! \brief uninitialize the entire environment.
816  * In practice, signal the thread and give it a bit of time to
817  * complete, giving up if it gets stuck. Because uninit
818  * is called from hangup with the channel locked, and the thread
819  * uses the chan lock, we need to unlock here. This is unsafe,
820  * and we should really use refcounts for the channels.
821  */
822 void console_video_uninit(struct video_desc *env)
823 {
824         int i, t = 100; /* initial wait is shorter, than make it longer */
825         env->shutdown = 1;
826         for (i=0; env->shutdown && i < 10; i++) {
827                 ast_channel_unlock(env->owner);
828                 usleep(t);
829                 t = 1000000;
830                 ast_channel_lock(env->owner);
831         }
832         env->owner = NULL;
833 }
834
835 /*! fill an AVPicture from our fbuf info, as it is required by
836  * the image conversion routines in ffmpeg.
837  * XXX This depends on the format.
838  */
839 static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p)
840 {
841         /* provide defaults for commonly used formats */
842         int l4 = b->w * b->h/4; /* size of U or V frame */
843         int len = b->w;         /* Y linesize, bytes */
844         int luv = b->w/2;       /* U/V linesize, bytes */
845
846         bzero(p, sizeof(*p));
847         switch (b->pix_fmt) {
848         case PIX_FMT_RGB555:
849         case PIX_FMT_RGB565:
850                 len *= 2;
851                 luv = 0;
852                 break;
853         case PIX_FMT_RGBA32:
854                 len *= 4;
855                 luv = 0;
856                 break;
857         case PIX_FMT_YUYV422:   /* Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr */
858                 len *= 2;       /* all data in first plane, probably */
859                 luv = 0;
860                 break;
861         }
862         p->data[0] = b->data;
863         p->linesize[0] = len;
864         /* these are only valid for component images */
865         p->data[1] = luv ? b->data + 4*l4 : b->data+len;
866         p->data[2] = luv ? b->data + 5*l4 : b->data+len;
867         p->linesize[1] = luv;
868         p->linesize[2] = luv;
869         return p;
870 }
871
872 /*! convert/scale between an input and an output format.
873  * Old version of ffmpeg only have img_convert, which does not rescale.
874  * New versions use sws_scale which does both.
875  */
876 static void my_scale(struct fbuf_t *in, AVPicture *p_in,
877         struct fbuf_t *out, AVPicture *p_out)
878 {
879         AVPicture my_p_in, my_p_out;
880
881         if (p_in == NULL)
882                 p_in = fill_pict(in, &my_p_in);
883         if (p_out == NULL)
884                 p_out = fill_pict(out, &my_p_out);
885
886 #ifdef OLD_FFMPEG
887         /* XXX img_convert is deprecated, and does not do rescaling */
888         img_convert(p_out, out->pix_fmt,
889                 p_in, in->pix_fmt, in->w, in->h);
890 #else /* XXX replacement */
891     {
892         struct SwsContext *convert_ctx;
893
894         convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
895                 out->w, out->h, out->pix_fmt,
896                 SWS_BICUBIC, NULL, NULL, NULL);
897         if (convert_ctx == NULL) {
898                 ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
899                 return;
900         }
901         if (0)
902                 ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
903                         in->pix_fmt, in->w, in->h, out->pix_fmt, out->w, out->h);
904         sws_scale(convert_ctx,
905                 p_in->data, p_in->linesize,
906                 in->w, in->h, /* src slice */
907                 p_out->data, p_out->linesize);
908
909         sws_freeContext(convert_ctx);
910     }
911 #endif /* XXX replacement */
912 }
913
914 struct video_desc *get_video_desc(struct ast_channel *c);
915
916 /*
917  * This function is called (by asterisk) for each video packet
918  * coming from the network (the 'in' path) that needs to be processed.
919  * We need to reconstruct the entire video frame before we can decode it.
920  * After a video packet is received we have to:
921  * - extract the bitstream with pre_process_data()
922  * - append the bitstream to a buffer
923  * - if the fragment is the last (RTP Marker) we decode it with decode_video()
924  * - after the decoding is completed we display the decoded frame with show_frame()
925  */
926 int console_write_video(struct ast_channel *chan, struct ast_frame *f);
927 int console_write_video(struct ast_channel *chan, struct ast_frame *f)
928 {
929         struct video_desc *env = get_video_desc(chan);
930         struct video_in_desc *v = &env->in;
931
932         if (!env->gui)  /* no gui, no rendering */
933                 return 0;
934         if (v->dec == NULL) {   /* try to get the codec */
935                 v->dec = map_video_codec(f->subclass & ~1);
936                 if (v->dec == NULL) {
937                         ast_log(LOG_WARNING, "cannot find video codec, drop input 0x%x\n", f->subclass);
938                         return 0;
939                 }
940                 if (video_in_init(v, v->dec->format)) {
941                         /* This is not fatal, but we won't have incoming video */
942                         ast_log(LOG_WARNING, "Cannot initialize input decoder\n");
943                         v->dec = NULL;
944                         return 0;
945                 }
946         }
947         if (v->dec_ctx == NULL) {
948                 ast_log(LOG_WARNING, "cannot decode, dropping frame\n");
949                 return 0;       /* error */
950         }
951
952         if (v->dec_in_cur == NULL)      /* no buffer for incoming frames, drop */
953                 return 0;
954 #if defined(DROP_PACKETS) && DROP_PACKETS > 0
955         /* Simulate lost packets */
956         if ((random() % 10000) <= 100*DROP_PACKETS) {
957                 ast_log(LOG_NOTICE, "Packet lost [%d]\n", f->seqno);
958                 return 0;
959         }
960 #endif
961         if (v->discard) {
962                 /*
963                  * In discard mode, drop packets until we find one with
964                  * the RTP marker set (which is the end of frame).
965                  * Note that the RTP marker flag is sent as the LSB of the
966                  * subclass, which is a  bitmask of formats. The low bit is
967                  * normally used for audio so there is no interference.
968                  */
969                 if (f->subclass & 0x01) {
970                         v->dec_in_cur->used = 0;
971                         v->dec_in_cur->ebit = 0;
972                         v->next_seq = f->seqno + 1;     /* wrap at 16 bit */
973                         v->discard = 0;
974                         ast_log(LOG_WARNING, "out of discard mode, frame %d\n", f->seqno);
975                 }
976                 return 0;
977         }
978
979         /*
980          * Only in-order fragments will be accepted. Remember seqno
981          * has 16 bit so there is wraparound. Also, ideally we could
982          * accept a bit of reordering, but at the moment we don't.
983          */
984         if (v->next_seq != f->seqno) {
985                 ast_log(LOG_WARNING, "discarding frame out of order, %d %d\n",
986                         v->next_seq, f->seqno);
987                 v->discard = 1;
988                 return 0;
989         }
990         v->next_seq++;
991
992         if (f->data == NULL || f->datalen < 2) {
993                 ast_log(LOG_WARNING, "empty video frame, discard\n");
994                 return 0;
995         }
996         if (v->dec->dec_decap(v->dec_in_cur, f->data, f->datalen)) {
997                 ast_log(LOG_WARNING, "error in dec_decap, enter discard\n");
998                 v->discard = 1;
999         }
1000         if (f->subclass & 0x01) {       // RTP Marker
1001                 /* prepare to decode: advance the buffer so the video thread knows. */
1002                 struct fbuf_t *tmp = v->dec_in_cur;     /* store current pointer */
1003                 ast_mutex_lock(&v->dec_in_lock);
1004                 if (++v->dec_in_cur == &v->dec_in[N_DEC_IN])    /* advance to next, circular */
1005                         v->dec_in_cur = &v->dec_in[0];
1006                 if (v->dec_in_dpy == NULL) {    /* were not displaying anything, so set it */
1007                         v->dec_in_dpy = tmp;
1008                 } else if (v->dec_in_dpy == v->dec_in_cur) { /* current slot is busy */
1009                         v->dec_in_cur = NULL;
1010                 }
1011                 ast_mutex_unlock(&v->dec_in_lock);
1012         }
1013         return 0;
1014 }
1015
1016
1017 /*! \brief read a frame from webcam or X11 through video_read(),
1018  * display it,  then encode and split it.
1019  * Return a list of ast_frame representing the video fragments.
1020  * The head pointer is returned by the function, the tail pointer
1021  * is returned as an argument.
1022  */
1023 static struct ast_frame *get_video_frames(struct video_desc *env, struct ast_frame **tail)
1024 {
1025         struct video_out_desc *v = &env->out;
1026         struct ast_frame *dummy;
1027
1028         if (!v->loc_src.data) {
1029                 static volatile int a = 0;
1030                 if (a++ < 2)
1031                         ast_log(LOG_WARNING, "fail, no loc_src buffer\n");
1032                 return NULL;
1033         }
1034         if (!video_read(v))
1035                 return NULL;    /* can happen, e.g. we are reading too early */
1036
1037         if (tail == NULL)
1038                 tail = &dummy;
1039         *tail = NULL;
1040         /* Scale the video for the encoder, then use it for local rendering
1041          * so we will see the same as the remote party.
1042          */
1043         my_scale(&v->loc_src, NULL, &v->enc_in, NULL);
1044         show_frame(env, WIN_LOCAL);
1045         if (!v->sendvideo)
1046                 return NULL;
1047         if (v->enc_out.data == NULL) {
1048                 static volatile int a = 0;
1049                 if (a++ < 2)
1050                         ast_log(LOG_WARNING, "fail, no encbuf\n");
1051                 return NULL;
1052         }
1053         v->enc->enc_run(v);
1054         return v->enc->enc_encap(v, tail);
1055 }
1056
1057 /*
1058  * Helper thread to periodically poll the video source and enqueue the
1059  * generated frames to the channel's queue.
1060  * Using a separate thread also helps because the encoding can be
1061  * computationally expensive so we don't want to starve the main thread.
1062  */
1063 static void *video_thread(void *arg)
1064 {
1065         struct video_desc *env = arg;
1066         int count = 0;
1067         char save_display[128] = "";
1068
1069         /* if sdl_videodriver is set, override the environment. Also,
1070          * if it contains 'console' override DISPLAY around the call to SDL_Init
1071          * so we use the console as opposed to the x11 version of aalib
1072          */
1073         if (!ast_strlen_zero(env->sdl_videodriver)) { /* override */
1074                 const char *s = getenv("DISPLAY");
1075                 setenv("SDL_VIDEODRIVER", env->sdl_videodriver, 1);
1076                 if (s && !strcasecmp(env->sdl_videodriver, "aalib-console")) {
1077                         ast_copy_string(save_display, s, sizeof(save_display));
1078                         unsetenv("DISPLAY");
1079                 }
1080         }
1081         sdl_setup(env);
1082         if (!ast_strlen_zero(save_display))
1083                 setenv("DISPLAY", save_display, 1);
1084
1085         /* initialize grab coordinates */
1086         env->out.loc_src.x = 0;
1087         env->out.loc_src.y = 0;
1088
1089         /* reset the pointers to the current decoded image */
1090         env->in.dec_in_cur = &env->in.dec_in[0];
1091         env->in.dec_in_dpy = NULL;      /* nothing to display */
1092         ast_mutex_init(&env->in.dec_in_lock);   /* used to sync decoder and renderer */
1093
1094         if (video_open(&env->out)) {
1095                 ast_log(LOG_WARNING, "cannot open local video source\n");
1096         } else {
1097                 /* try to register the fd. Unfortunately, if the webcam
1098                  * driver does not support select/poll we are out of luck.
1099                  */
1100                 if (env->out.fd >= 0)
1101                         ast_channel_set_fd(env->owner, 1, env->out.fd);
1102                 video_out_init(env);
1103         }
1104
1105         for (;;) {
1106                 struct timeval t = { 0, 50000 };        /* XXX 20 times/sec */
1107                 struct ast_frame *p, *f;
1108                 struct video_in_desc *v = &env->in;
1109                 struct ast_channel *chan = env->owner;
1110                 int fd = chan->alertpipe[1];
1111                 char *caption = NULL, buf[160];
1112
1113                 /* determine if video format changed */
1114                 if (count++ % 10 == 0) {
1115                         if (env->out.sendvideo)
1116                             sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
1117                                 env->out.videodevice, env->codec_name,
1118                                 env->out.enc_in.w, env->out.enc_in.h,
1119                                 env->out.fps, env->out.bitrate/1000);
1120                         else
1121                             sprintf(buf, "hold");
1122                         caption = buf;
1123                 }
1124
1125                 /* manage keypad events */
1126                 /* XXX here we should always check for events,
1127                 * otherwise the drag will not work */ 
1128                 if (env->gui)
1129                         eventhandler(env, caption);
1130  
1131                 /* sleep for a while */
1132                 ast_select(0, NULL, NULL, NULL, &t);
1133
1134                 /*
1135                  * While there is something to display, call the decoder and free
1136                  * the buffer, possibly enabling the receiver to store new data.
1137                  */
1138                 while (v->dec_in_dpy) {
1139                         struct fbuf_t *tmp = v->dec_in_dpy;     /* store current pointer */
1140
1141                         if (v->dec->dec_run(v, tmp))
1142                                 show_frame(env, WIN_REMOTE);
1143                         tmp->used = 0;  /* mark buffer as free */
1144                         tmp->ebit = 0;
1145                         ast_mutex_lock(&v->dec_in_lock);
1146                         if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN])    /* advance to next, circular */
1147                                 v->dec_in_dpy = &v->dec_in[0];
1148
1149                         if (v->dec_in_cur == NULL)      /* receiver was idle, enable it... */
1150                                 v->dec_in_cur = tmp;    /* using the slot just freed */
1151                         else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
1152                                 v->dec_in_dpy = NULL;   /* nothing more to display */
1153                         ast_mutex_unlock(&v->dec_in_lock);
1154                 }
1155
1156
1157                 f = get_video_frames(env, &p);  /* read and display */
1158                 if (!f)
1159                         continue;
1160                 if (env->shutdown)
1161                         break;
1162                 chan = env->owner;
1163                 ast_channel_lock(chan);
1164
1165                 /* AST_LIST_INSERT_TAIL is only good for one frame, cannot use here */
1166                 if (chan->readq.first == NULL) {
1167                         chan->readq.first = f;
1168                 } else {
1169                         chan->readq.last->frame_list.next = f;
1170                 }
1171                 chan->readq.last = p;
1172                 /*
1173                  * more or less same as ast_queue_frame, but extra
1174                  * write on the alertpipe to signal frames.
1175                  */
1176                 if (fd > -1) {
1177                         int blah = 1, l = sizeof(blah);
1178                         for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
1179                                 if (write(fd, &blah, l) != l)
1180                                         ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
1181                                             chan->name, f->frametype, f->subclass, strerror(errno));
1182                         }
1183                 }
1184                 ast_channel_unlock(chan);
1185         }
1186         /* thread terminating, here could call the uninit */
1187         /* uninitialize the local and remote video environments */
1188         video_in_uninit(&env->in);
1189         video_out_uninit(&env->out);
1190
1191         if (env->gui)
1192                 env->gui = cleanup_sdl(env->gui);
1193         ast_mutex_destroy(&(env->in.dec_in_lock));
1194         env->shutdown = 0;
1195         return NULL;
1196 }
1197
1198 static void copy_geometry(struct fbuf_t *src, struct fbuf_t *dst)
1199 {
1200         if (dst->w == 0)
1201                 dst->w = src->w;
1202         if (dst->h == 0)
1203                 dst->h = src->h;
1204 }
1205
1206 /*! initialize the video environment.
1207  * Apart from the formats (constant) used by sdl and the codec,
1208  * we use enc_in as the basic geometry.
1209  */
1210 static void init_env(struct video_desc *env)
1211 {
1212         struct fbuf_t *c = &(env->out.loc_src);         /* local source */
1213         struct fbuf_t *ei = &(env->out.enc_in);         /* encoder input */
1214         struct fbuf_t *ld = &(env->out.loc_dpy);        /* local display */
1215         struct fbuf_t *rd = &(env->in.rem_dpy);         /* remote display */
1216
1217         c->pix_fmt = PIX_FMT_YUV420P;   /* default - camera format */
1218         ei->pix_fmt = PIX_FMT_YUV420P;  /* encoder input */
1219         if (ei->w == 0 || ei->h == 0) {
1220                 ei->w = 352;
1221                 ei->h = 288;
1222         }
1223         ld->pix_fmt = rd->pix_fmt = PIX_FMT_YUV420P; /* sdl format */
1224         /* inherit defaults */
1225         copy_geometry(ei, c);   /* camera inherits from encoder input */
1226         copy_geometry(ei, rd);  /* remote display inherits from encoder input */
1227         copy_geometry(rd, ld);  /* local display inherits from remote display */
1228 }
1229
1230 /*!
1231  * The first call to the video code, called by oss_new() or similar.
1232  * Here we initialize the various components we use, namely SDL for display,
1233  * ffmpeg for encoding/decoding, and a local video source.
1234  * We do our best to progress even if some of the components are not
1235  * available.
1236  */
1237 void console_video_start(struct video_desc *env, struct ast_channel *owner)
1238 {
1239         if (env == NULL)        /* video not initialized */
1240                 return;
1241         if (owner == NULL)      /* nothing to do if we don't have a channel */
1242                 return;
1243         env->owner = owner;
1244         init_env(env);
1245         env->out.enc = map_config_video_format(env->codec_name);
1246
1247         ast_log(LOG_WARNING, "start video out %s %dx%d\n",
1248                 env->codec_name, env->out.enc_in.w,  env->out.enc_in.h);
1249         /*
1250          * Register all codecs supported by the ffmpeg library.
1251          * We only need to do it once, but probably doesn't
1252          * harm to do it multiple times.
1253          */
1254         avcodec_init();
1255         avcodec_register_all();
1256         av_log_set_level(AV_LOG_ERROR); /* only report errors */
1257
1258         if (env->out.fps == 0) {
1259                 env->out.fps = 15;
1260                 ast_log(LOG_WARNING, "fps unset, forcing to %d\n", env->out.fps);
1261         }
1262         if (env->out.bitrate == 0) {
1263                 env->out.bitrate = 65000;
1264                 ast_log(LOG_WARNING, "bitrate unset, forcing to %d\n", env->out.bitrate);
1265         }
1266
1267         ast_pthread_create_background(&env->vthread, NULL, video_thread, env);
1268 }
1269
1270 /*
1271  * Parse a geometry string, accepting also common names for the formats.
1272  * Trick: if we have a leading > or < and a numeric geometry,
1273  * return the larger or smaller one.
1274  * E.g. <352x288 gives the smaller one, 320x240
1275  */
1276 static int video_geom(struct fbuf_t *b, const char *s)
1277 {
1278         int w = 0, h = 0;
1279
1280         static struct {
1281                 const char *s; int w; int h;
1282         } *fp, formats[] = {
1283                 {"vga",         640, 480 },
1284                 {"cif",         352, 288 },
1285                 {"qvga",        320, 240 },
1286                 {"qcif",        176, 144 },
1287                 {"sqcif",       128, 96 },
1288                 {NULL,          0, 0 },
1289         };
1290         if (*s == '<' || *s == '>')
1291                 sscanf(s+1,"%dx%d", &w, &h);
1292         for (fp = formats; fp->s; fp++) {
1293                 if (*s == '>') {        /* look for a larger one */
1294                         if (fp->w <= w) {
1295                                 if (fp > formats)
1296                                         fp--; /* back one step if possible */
1297                                 break;
1298                         }
1299                 } else if (*s == '<') { /* look for a smaller one */
1300                         if (fp->w < w)
1301                                 break;
1302                 } else if (!strcasecmp(s, fp->s)) { /* look for a string */
1303                         break;
1304                 }
1305         }
1306         if (*s == '<' && fp->s == NULL) /* smallest */
1307                 fp--;
1308         if (fp->s) {
1309                 b->w = fp->w;
1310                 b->h = fp->h;
1311         } else if (sscanf(s, "%dx%d", &b->w, &b->h) != 2) {
1312                 ast_log(LOG_WARNING, "Invalid video_size %s, using 352x288\n", s);
1313                 b->w = 352;
1314                 b->h = 288;
1315         }
1316         return 0;
1317 }
1318
1319 /* extend ast_cli with video commands. Called by console_video_config */
1320 int console_video_cli(struct video_desc *env, const char *var, int fd)
1321 {
1322         if (env == NULL)
1323                 return 1;       /* unrecognised */
1324
1325         if (!strcasecmp(var, "videodevice")) {
1326                 ast_cli(fd, "videodevice is [%s]\n", env->out.videodevice);
1327         } else if (!strcasecmp(var, "videocodec")) {
1328                 ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
1329         } else if (!strcasecmp(var, "sendvideo")) {
1330                 ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
1331         } else if (!strcasecmp(var, "video_size")) {
1332                 ast_cli(fd, "sizes: video %dx%d camera %dx%d local %dx%d remote %dx%d in %dx%d\n",
1333                         env->out.enc_in.w, env->out.enc_in.h,
1334                         env->out.loc_src.w, env->out.loc_src.h,
1335                         env->out.loc_dpy.w, env->out.loc_dpy.h,
1336                         env->in.rem_dpy.w, env->in.rem_dpy.h,
1337                         env->in.dec_out.w, env->in.dec_out.h);
1338         } else if (!strcasecmp(var, "bitrate")) {
1339                 ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
1340         } else if (!strcasecmp(var, "qmin")) {
1341                 ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
1342         } else if (!strcasecmp(var, "fps")) {
1343                 ast_cli(fd, "fps is [%d]\n", env->out.fps);
1344         } else {
1345                 return 1;       /* unrecognised */
1346         }
1347         return 0;       /* recognised */
1348 }
1349
1350 /*! parse config command for video support. */
1351 int console_video_config(struct video_desc **penv,
1352         const char *var, const char *val)
1353 {
1354         struct video_desc *env;
1355
1356         if (penv == NULL) {
1357                 ast_log(LOG_WARNING, "bad argument penv=NULL\n");
1358                 return 1;       /* error */
1359         }
1360         /* allocate the video descriptor first time we get here */
1361         env = *penv;
1362         if (env == NULL) {
1363                 env = *penv = ast_calloc(1, sizeof(struct video_desc));
1364                 if (env == NULL) {
1365                         ast_log(LOG_WARNING, "fail to allocate video_desc\n");
1366                         return 1;       /* error */
1367                 
1368                 }
1369                 /* set default values */
1370                 ast_copy_string(env->out.videodevice, "X11", sizeof(env->out.videodevice));
1371                 env->out.fps = 5;
1372                 env->out.bitrate = 65000;
1373                 env->out.sendvideo = 1;
1374                 env->out.qmin = 3;
1375         }
1376         CV_START(var, val);
1377         CV_STR("videodevice", env->out.videodevice);
1378         CV_BOOL("sendvideo", env->out.sendvideo);
1379         CV_F("video_size", video_geom(&env->out.enc_in, val));
1380         CV_F("camera_size", video_geom(&env->out.loc_src, val));
1381         CV_F("local_size", video_geom(&env->out.loc_dpy, val));
1382         CV_F("remote_size", video_geom(&env->in.rem_dpy, val));
1383         CV_STR("keypad", env->keypad_file);
1384         CV_F("region", keypad_cfg_read(env->gui, val));
1385         CV_STR("keypad_font", env->keypad_font);
1386         CV_STR("sdl_videodriver", env->sdl_videodriver);
1387         CV_UINT("fps", env->out.fps);
1388         CV_UINT("bitrate", env->out.bitrate);
1389         CV_UINT("qmin", env->out.qmin);
1390         CV_STR("videocodec", env->codec_name);
1391         return 1;       /* nothing found */
1392
1393         CV_END;         /* the 'nothing found' case */
1394         return 0;               /* found something */
1395 }
1396
1397 #endif  /* video support */