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