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