more localization of sdl stuff
[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  * In principle SDL is optional too (used for rendering only, but we
92  * could still source data withouth it), however at the moment it is required.
93  */
94 #if !defined(HAVE_VIDEO_CONSOLE) || !defined(HAVE_FFMPEG) || !defined(HAVE_SDL)
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         if (SDL_Init(SDL_INIT_VIDEO)) {
1082                 ast_log(LOG_WARNING, "Could not initialize SDL - %s\n",
1083                         SDL_GetError());
1084                 /* again not fatal, just we won't display anything */
1085         } else {
1086                 sdl_setup(env);
1087         }
1088         ast_mutex_init(&env->in.dec_in_lock);
1089         if (!ast_strlen_zero(save_display))
1090                 setenv("DISPLAY", save_display, 1);
1091
1092         if (video_open(&env->out)) {
1093                 ast_log(LOG_WARNING, "cannot open local video source\n");
1094         } else {
1095                 /* try to register the fd. Unfortunately, if the webcam
1096                  * driver does not support select/poll we are out of luck.
1097                  */
1098                 if (env->out.fd >= 0)
1099                         ast_channel_set_fd(env->owner, 1, env->out.fd);
1100                 video_out_init(env);
1101         }
1102
1103         for (;;) {
1104                 /* XXX 20 times/sec */
1105                 struct timeval t = { 0, 50000 };
1106                 struct ast_frame *p, *f;
1107                 struct video_in_desc *v = &env->in;
1108                 struct ast_channel *chan = env->owner;
1109                 int fd = chan->alertpipe[1];
1110
1111                 /* determine if video format changed */
1112                 if (count++ % 10 == 0) {
1113                         char buf[160];
1114                         if (env->out.sendvideo)
1115                             sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
1116                                 env->out.videodevice, env->codec_name,
1117                                 env->out.enc_in.w, env->out.enc_in.h,
1118                                 env->out.fps, env->out.bitrate/1000);
1119                         else
1120                             sprintf(buf, "hold");
1121                         SDL_WM_SetCaption(buf, NULL);
1122                 }
1123
1124                 /* manage keypad events */
1125                 /* XXX here we should always check for events,
1126                 * otherwise the drag will not work */ 
1127                 if (env->gui)
1128                         eventhandler(env);
1129  
1130                 /* sleep for a while */
1131                 ast_select(0, NULL, NULL, NULL, &t);
1132
1133                 if (env->gui)
1134                         SDL_UpdateRects(env->gui->screen, 1, &env->gui->win[WIN_KEYPAD].rect);// XXX inefficient
1135                 /*
1136                  * While there is something to display, call the decoder and free
1137                  * the buffer, possibly enabling the receiver to store new data.
1138                  */
1139                 while (v->dec_in_dpy) {
1140                         struct fbuf_t *tmp = v->dec_in_dpy;     /* store current pointer */
1141
1142                         if (v->dec->dec_run(v, tmp))
1143                                 show_frame(env, WIN_REMOTE);
1144                         tmp->used = 0;  /* mark buffer as free */
1145                         tmp->ebit = 0;
1146                         ast_mutex_lock(&v->dec_in_lock);
1147                         if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN])    /* advance to next, circular */
1148                                 v->dec_in_dpy = &v->dec_in[0];
1149
1150                         if (v->dec_in_cur == NULL)      /* receiver was idle, enable it... */
1151                                 v->dec_in_cur = tmp;    /* using the slot just freed */
1152                         else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
1153                                 v->dec_in_dpy = NULL;   /* nothing more to display */
1154                         ast_mutex_unlock(&v->dec_in_lock);
1155                 }
1156
1157
1158                 f = get_video_frames(env, &p);  /* read and display */
1159                 if (!f)
1160                         continue;
1161                 if (env->shutdown)
1162                         break;
1163                 chan = env->owner;
1164                 ast_channel_lock(chan);
1165
1166                 /* AST_LIST_INSERT_TAIL is only good for one frame, cannot use here */
1167                 if (chan->readq.first == NULL) {
1168                         chan->readq.first = f;
1169                 } else {
1170                         chan->readq.last->frame_list.next = f;
1171                 }
1172                 chan->readq.last = p;
1173                 /*
1174                  * more or less same as ast_queue_frame, but extra
1175                  * write on the alertpipe to signal frames.
1176                  */
1177                 if (fd > -1) {
1178                         int blah = 1, l = sizeof(blah);
1179                         for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
1180                                 if (write(fd, &blah, l) != l)
1181                                         ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
1182                                             chan->name, f->frametype, f->subclass, strerror(errno));
1183                         }
1184                 }
1185                 ast_channel_unlock(chan);
1186         }
1187         /* thread terminating, here could call the uninit */
1188         /* uninitialize the local and remote video environments */
1189         video_in_uninit(&env->in);
1190         video_out_uninit(&env->out);
1191
1192         if (env->gui)
1193                 cleanup_sdl(env);
1194         ast_mutex_destroy(&(env->in.dec_in_lock));
1195         env->shutdown = 0;
1196         return NULL;
1197 }
1198
1199 static void copy_geometry(struct fbuf_t *src, struct fbuf_t *dst)
1200 {
1201         if (dst->w == 0)
1202                 dst->w = src->w;
1203         if (dst->h == 0)
1204                 dst->h = src->h;
1205 }
1206
1207 /*! initialize the video environment.
1208  * Apart from the formats (constant) used by sdl and the codec,
1209  * we use enc_in as the basic geometry.
1210  */
1211 static void init_env(struct video_desc *env)
1212 {
1213         struct fbuf_t *c = &(env->out.loc_src);         /* local source */
1214         struct fbuf_t *ei = &(env->out.enc_in);         /* encoder input */
1215         struct fbuf_t *ld = &(env->out.loc_dpy);        /* local display */
1216         struct fbuf_t *rd = &(env->in.rem_dpy);         /* remote display */
1217
1218         c->pix_fmt = PIX_FMT_YUV420P;   /* default - camera format */
1219         ei->pix_fmt = PIX_FMT_YUV420P;  /* encoder input */
1220         if (ei->w == 0 || ei->h == 0) {
1221                 ei->w = 352;
1222                 ei->h = 288;
1223         }
1224         ld->pix_fmt = rd->pix_fmt = PIX_FMT_YUV420P; /* sdl format */
1225         /* inherit defaults */
1226         copy_geometry(ei, c);   /* camera inherits from encoder input */
1227         copy_geometry(ei, rd);  /* remote display inherits from encoder input */
1228         copy_geometry(rd, ld);  /* local display inherits from remote display */
1229 }
1230
1231 /*!
1232  * The first call to the video code, called by oss_new() or similar.
1233  * Here we initialize the various components we use, namely SDL for display,
1234  * ffmpeg for encoding/decoding, and a local video source.
1235  * We do our best to progress even if some of the components are not
1236  * available.
1237  */
1238 void console_video_start(struct video_desc *env, struct ast_channel *owner)
1239 {
1240         if (env == NULL)        /* video not initialized */
1241                 return;
1242         if (owner == NULL)      /* nothing to do if we don't have a channel */
1243                 return;
1244         env->owner = owner;
1245         init_env(env);
1246         env->out.enc = map_config_video_format(env->codec_name);
1247
1248         ast_log(LOG_WARNING, "start video out %s %dx%d\n",
1249                 env->codec_name, env->out.enc_in.w,  env->out.enc_in.h);
1250         /*
1251          * Register all codecs supported by the ffmpeg library.
1252          * We only need to do it once, but probably doesn't
1253          * harm to do it multiple times.
1254          */
1255         avcodec_init();
1256         avcodec_register_all();
1257         av_log_set_level(AV_LOG_ERROR); /* only report errors */
1258
1259         if (env->out.fps == 0) {
1260                 env->out.fps = 15;
1261                 ast_log(LOG_WARNING, "fps unset, forcing to %d\n", env->out.fps);
1262         }
1263         if (env->out.bitrate == 0) {
1264                 env->out.bitrate = 65000;
1265                 ast_log(LOG_WARNING, "bitrate unset, forcing to %d\n", env->out.bitrate);
1266         }
1267
1268         ast_pthread_create_background(&env->vthread, NULL, video_thread, env);
1269 }
1270
1271 /*
1272  * Parse a geometry string, accepting also common names for the formats.
1273  * Trick: if we have a leading > or < and a numeric geometry,
1274  * return the larger or smaller one.
1275  * E.g. <352x288 gives the smaller one, 320x240
1276  */
1277 static int video_geom(struct fbuf_t *b, const char *s)
1278 {
1279         int w = 0, h = 0;
1280
1281         static struct {
1282                 const char *s; int w; int h;
1283         } *fp, formats[] = {
1284                 {"vga",         640, 480 },
1285                 {"cif",         352, 288 },
1286                 {"qvga",        320, 240 },
1287                 {"qcif",        176, 144 },
1288                 {"sqcif",       128, 96 },
1289                 {NULL,          0, 0 },
1290         };
1291         if (*s == '<' || *s == '>')
1292                 sscanf(s+1,"%dx%d", &w, &h);
1293         for (fp = formats; fp->s; fp++) {
1294                 if (*s == '>') {        /* look for a larger one */
1295                         if (fp->w <= w) {
1296                                 if (fp > formats)
1297                                         fp--; /* back one step if possible */
1298                                 break;
1299                         }
1300                 } else if (*s == '<') { /* look for a smaller one */
1301                         if (fp->w < w)
1302                                 break;
1303                 } else if (!strcasecmp(s, fp->s)) { /* look for a string */
1304                         break;
1305                 }
1306         }
1307         if (*s == '<' && fp->s == NULL) /* smallest */
1308                 fp--;
1309         if (fp->s) {
1310                 b->w = fp->w;
1311                 b->h = fp->h;
1312         } else if (sscanf(s, "%dx%d", &b->w, &b->h) != 2) {
1313                 ast_log(LOG_WARNING, "Invalid video_size %s, using 352x288\n", s);
1314                 b->w = 352;
1315                 b->h = 288;
1316         }
1317         return 0;
1318 }
1319
1320 /* extend ast_cli with video commands. Called by console_video_config */
1321 int console_video_cli(struct video_desc *env, const char *var, int fd)
1322 {
1323         if (env == NULL)
1324                 return 1;       /* unrecognised */
1325
1326         if (!strcasecmp(var, "videodevice")) {
1327                 ast_cli(fd, "videodevice is [%s]\n", env->out.videodevice);
1328         } else if (!strcasecmp(var, "videocodec")) {
1329                 ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
1330         } else if (!strcasecmp(var, "sendvideo")) {
1331                 ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
1332         } else if (!strcasecmp(var, "video_size")) {
1333                 ast_cli(fd, "sizes: video %dx%d camera %dx%d local %dx%d remote %dx%d in %dx%d\n",
1334                         env->out.enc_in.w, env->out.enc_in.h,
1335                         env->out.loc_src.w, env->out.loc_src.h,
1336                         env->out.loc_dpy.w, env->out.loc_src.h,
1337                         env->in.rem_dpy.w, env->in.rem_dpy.h,
1338                         env->in.dec_out.w, env->in.dec_out.h);
1339         } else if (!strcasecmp(var, "bitrate")) {
1340                 ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
1341         } else if (!strcasecmp(var, "qmin")) {
1342                 ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
1343         } else if (!strcasecmp(var, "fps")) {
1344                 ast_cli(fd, "fps is [%d]\n", env->out.fps);
1345         } else {
1346                 return 1;       /* unrecognised */
1347         }
1348         return 0;       /* recognised */
1349 }
1350
1351 /*! parse config command for video support. */
1352 int console_video_config(struct video_desc **penv,
1353         const char *var, const char *val)
1354 {
1355         struct video_desc *env;
1356
1357         if (penv == NULL) {
1358                 ast_log(LOG_WARNING, "bad argument penv=NULL\n");
1359                 return 1;       /* error */
1360         }
1361         /* allocate the video descriptor first time we get here */
1362         env = *penv;
1363         if (env == NULL) {
1364                 env = *penv = ast_calloc(1, sizeof(struct video_desc));
1365                 if (env == NULL) {
1366                         ast_log(LOG_WARNING, "fail to allocate video_desc\n");
1367                         return 1;       /* error */
1368                 
1369                 }
1370                 /* set default values */
1371                 ast_copy_string(env->out.videodevice, "X11", sizeof(env->out.videodevice));
1372                 env->out.fps = 5;
1373                 env->out.bitrate = 65000;
1374                 env->out.sendvideo = 1;
1375                 env->out.qmin = 3;
1376         }
1377         CV_START(var, val);
1378         CV_STR("videodevice", env->out.videodevice);
1379         CV_BOOL("sendvideo", env->out.sendvideo);
1380         CV_F("video_size", video_geom(&env->out.enc_in, val));
1381         CV_F("camera_size", video_geom(&env->out.loc_src, val));
1382         CV_F("local_size", video_geom(&env->out.loc_dpy, val));
1383         CV_F("remote_size", video_geom(&env->in.rem_dpy, val));
1384         CV_STR("keypad", env->keypad_file);
1385         CV_F("region", keypad_cfg_read(env->gui, val));
1386         CV_STR("keypad_font", env->keypad_font);
1387         CV_STR("sdl_videodriver", env->sdl_videodriver);
1388         CV_UINT("fps", env->out.fps);
1389         CV_UINT("bitrate", env->out.bitrate);
1390         CV_UINT("qmin", env->out.qmin);
1391         CV_STR("videocodec", env->codec_name);
1392         return 1;       /* nothing found */
1393
1394         CV_END;         /* the 'nothing found' case */
1395         return 0;               /* found something */
1396 }
1397
1398 #endif  /* video support */