Author: rizzo
Date: Thu Jul 26 11:34:55 2007
New Revision: 77314

URL: http://svn.digium.com/view/asterisk?view=rev&rev=77314
Log:
more webcam/video bits.
Add code to open a v4l device and read from it,
plus some debugging code to show various info
(when a frame is ready, its size, and so on).
All what's missing now it the call to the encoding
routines, and possibly a secondary SDL window for
the local stream.

Modified:
    team/rizzo/astobj2/channels/chan_oss.c

Modified: team/rizzo/astobj2/channels/chan_oss.c
URL: 
http://svn.digium.com/view/asterisk/team/rizzo/astobj2/channels/chan_oss.c?view=diff&rev=77314&r1=77313&r2=77314
==============================================================================
--- team/rizzo/astobj2/channels/chan_oss.c (original)
+++ team/rizzo/astobj2/channels/chan_oss.c Thu Jul 26 11:34:55 2007
@@ -42,6 +42,7 @@
  * experimental support to decode a video session.
  */
 //#define DROP_PACKETS 5       // if set, simulate this percentage of lost 
video packets
+#define HAVE_V4L       1
 #define HAVE_SDL       1
 #define HAVE_FFMPEG    1
 
@@ -84,13 +85,6 @@
 #include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
 
-#if HAVE_FFMPEG
-#include <ffmpeg/avcodec.h>
-#endif
-#if HAVE_SDL
-#include <SDL/SDL.h>
-#endif
-
 /* ringtones we use */
 #include "busy.h"
 #include "ringtone.h"
@@ -327,6 +321,9 @@
  * Examples for video encoding are at
 http://www.irisa.fr/texmex/people/dufouil/ffmpegdoxy/apiexample_8c-source.html
  */
+
+#include <ffmpeg/avcodec.h>
+#include <SDL/SDL.h>
 
 /* Structures for ffmpeg processing */
 /*
@@ -350,6 +347,19 @@
        int received;
 
        struct ast_frame *echo;
+
+       /* webcam support.
+        * videodevice and geometry are read from the config file.
+        * At the right time we try to open it and allocate a buffer.
+        * If we are successful, webcam_bufsize > 0 and we can read.
+        */
+       const char *videodevice;        /* pointer in the parent struct */
+       int w;                  /* geometry */
+       int h;
+       int webcam_fd;          /* file descriptor */
+       int webcam_bufsize;     /* buffer size, also total bytes per frame */
+       int webcam_ofs;         /* offset for next read */
+       char *webcam_imgbuf;    /* malloced area of size webcam_bufsize */
 };
 
 struct _cm {   /* map ffmpeg codec types to asterisk formats */
@@ -361,6 +371,124 @@
        { AST_FORMAT_H263_PLUS, CODEC_ID_H263 },
        { 0,                    0 },
 };
+
+/*! \brief support to open a webcam using video4linux1 and read()
+ *
+ */
+#if !defined(HAVE_V4L) || HAVE_V4L != 1
+/* stubs */
+static int webcam_open(struct video_desc *env)
+{
+       return -1;
+}
+static int webcam_read(struct video_desc *env)
+{
+       return 0;
+}
+
+#else
+
+/* the real thing */
+#include <linux/videodev.h>
+
+static int webcam_open(struct video_desc *env)
+{
+       int fd, i;
+       const char *device = env->videodevice;
+       struct video_window vw = { 0 }; /* camera attributes */
+       struct video_picture vp;
+
+       int bufsize;
+       char *imgbuf = NULL;
+
+       if (env->webcam_imgbuf)
+               return env->webcam_fd;
+
+       fd = open(device, O_RDONLY | O_NONBLOCK);
+       if (fd < 0) {
+               ast_log(LOG_WARNING, "error opening camera %s\n", device);
+               return fd;
+       }
+
+       i = fcntl(fd, F_GETFL);
+       if (-1 == fcntl(fd, F_GETFL, i | O_NONBLOCK)) {
+               ast_log(LOG_WARNING, "error F_SETFL for %s\n", device);
+               goto error;
+       }
+       /* set format */
+       vw.width = env->w;
+       vw.height = env->h;
+       bufsize = (vw.width * vw.height * 3)/2; /* yuv411 */
+       if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
+               ast_log(LOG_WARNING, "error setting format for %s\n", device);
+               goto error;
+       }
+       if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
+                ast_log(LOG_WARNING, "error reading picture info\n");
+                return -1;
+        }
+       ast_log(LOG_WARNING, "contrast %d bright %d colour %d hue %d whiteness 
%d palette %d\n",
+                vp.contrast, vp.brightness,
+                vp.colour, vp.hue,
+                vp.whiteness, vp.palette);
+       vp.palette = VIDEO_PALETTE_YUV420P;
+       if(ioctl(fd,VIDIOCSPICT,&vp) == -1) {
+               ast_log(LOG_WARNING, "error setting picture info\n");
+               goto error;
+        }
+       imgbuf = malloc(bufsize);
+       if (!imgbuf)
+               goto error;
+
+       env->webcam_fd = fd;
+       env->webcam_bufsize = bufsize;
+       env->webcam_ofs = 0;
+       env->webcam_imgbuf = imgbuf;
+       ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n", device, 
env->w, env->h, bufsize);
+       return fd;
+
+error:
+       if (fd >= 0)
+               close(fd);
+       if (imgbuf)
+               free(imgbuf);
+       env->webcam_fd = -1;
+       return -1;
+}
+
+/*! \brief complete a buffer from the webcam */
+static int webcam_read(struct video_desc *env)
+{
+       if (env->webcam_bufsize == 0)
+               return 0;
+
+       for (;;) {
+               int r, l = env->webcam_bufsize - env->webcam_ofs;
+               r = read(env->webcam_fd, env->webcam_imgbuf + env->webcam_ofs, 
l);
+               // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, 
l);
+               if (r < 0) {    /* read error */
+                       return 0;
+               }
+               if (r == 0)     /* no data */
+                       return 0;
+               env->webcam_ofs += r;
+               if (r == l) {
+                       env->webcam_ofs = 0; /* prepare for next frame */
+                       return env->webcam_bufsize;
+               }
+       }
+}
+#endif /* HAVE_V4L */
+
+static void show_frame(struct video_desc *env);
+
+static void webcam_encode(struct video_desc *env)
+{
+       struct timeval now = ast_tvnow();
+       ast_log(LOG_WARNING, "video frame ready at %d.%06d\n",
+               (int)now.tv_sec % 1000, (int)now.tv_usec);
+       show_frame(env);
+}
 
 /* Helper function to process incoming video.
  * For each incoming video call invoke ffmpeg_init() to intialize
@@ -372,18 +500,11 @@
  * to display the frame.
  *
  */
-/* Extract the bitstream from the RTP payload */
-static uint8_t *pre_process_data(uint8_t *, int *);
-/* Decode video frame once completed */
-static int decode_video(struct video_desc *);
-/* Dispaly decoded frame */
-static void show_frame(struct video_desc *);
 
 static struct video_desc *get_video_desc(struct ast_channel *c);
 
 /* Macros used as a wrapper around the actual video format we want to use */
 #define AST_FORMAT_CUSTOM (AST_FORMAT_H263_PLUS)
-static int write_video(struct ast_channel *chan, struct ast_frame *f);
 
 /*! \brief map an asterisk format into an ffmpeg one */
 static enum CodecID map_video_format(uint32_t ast_format)
@@ -498,8 +619,21 @@
        if(env->bmp)
                SDL_FreeYUVOverlay(env->bmp);
        SDL_Quit();
-       bzero(env, sizeof(struct video_desc));
-       env->initialized = 0;
+
+       if (env->webcam_imgbuf) {
+               free(env->webcam_imgbuf);
+               if (env->webcam_fd >= 0)
+               close(env->webcam_fd);
+       }
+       {       /* clear the struct but restore some fields */
+               const char *vd = env->videodevice;
+               int w = env->w, h = env->h;
+               bzero(env, sizeof(struct video_desc));
+               /* restore fields... */
+               env->videodevice = vd;
+               env->w = w;
+               env->h = h;
+       }
 }
 
 #define MAKE_MASK(bits)                ( (1<<(bits)) -1 )
@@ -585,6 +719,8 @@
        uint8_t *data;
        int datalen;
 
+       if (!len)
+               return 0;
        while(len) {
                ret = av_parser_parse(env->parser, env->context, &data, 
&datalen, aux, len, 0, 0);
                if(datalen) {
@@ -613,6 +749,8 @@
        AVPicture pict;
        SDL_Rect rect;
 
+       if (!env->initialized)
+               return;
        if(env->screen == NULL) {
                env->screen = SDL_SetVideoMode(env->context->width, 
env->context->height, 0, 0);
                if(!env->screen) {
@@ -638,7 +776,12 @@
                (AVPicture *)env->frame, env->context->pix_fmt,
                env->context->width, env->context->height);
        SDL_UnlockYUVOverlay(env->bmp);
-
+#if 0  /* more testing, overlay the received image with the local picture */
+       ast_log(LOG_WARNING, "show_frame: linesize %d %d %d\n", 
pict.linesize[0], pict.linesize[1], pict.linesize[2]);
+       if (env->webcam_imgbuf) {
+               bcopy(env->webcam_imgbuf, pict.data[0], 
env->context->width*env->context->height);
+       }
+#endif
        rect.x = 0; rect.y = 0;
        rect.w = env->context->width;
        rect.h = env->context->height;
@@ -661,16 +804,19 @@
        struct video_desc *env = get_video_desc(chan);
        struct timeval now = ast_tvnow();
        int i;
-       struct ast_frame *f1, **fp;
 
        if(!env->initialized)
                ffmpeg_init(env, f->subclass);
        if(!env->initialized)
                return -1;      /* error */
-       f1 = ast_frdup(f);
-       for (fp = &env->echo; (*fp) != NULL ; fp = &AST_LIST_NEXT((*fp), 
frame_list) )
-               ;
-       *fp = f1;
+
+       if (0) {        /* echo frames back to the sender */
+               struct ast_frame *f1, **fp;
+               f1 = ast_frdup(f);
+               for (fp = &env->echo; (*fp) != NULL ; fp = 
&AST_LIST_NEXT((*fp), frame_list) )
+                       ;
+               *fp = f1;
+       }
 
        i = ast_tvdiff_ms(now, env->ts);
        if (i > 1000) {
@@ -838,6 +984,7 @@
        int readpos;                            /*!< read position above */
        struct ast_frame read_f;        /*!< returned by oss_read */
 
+       char videodevice[64];
 #if HAVE_FFMPEG
        struct video_desc env;
 #endif
@@ -1237,6 +1384,8 @@
        res = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
        res = ioctl(fd, SNDCTL_DSP_SETTRIGGER, &res);
        /* it may fail if we are in half duplex, never mind */
+
+       fd = webcam_open(&o->env);
        return 0;
 }
 
@@ -1402,6 +1551,9 @@
        struct timeval tb;
 
        struct video_desc *env = get_video_desc(c);
+
+       if (webcam_read(env) && 0)
+               webcam_encode(env);     /* get frames and put them in the queue 
*/
        if (env->echo) {
                struct ast_frame *f1;
                int i = 0;
@@ -2039,9 +2191,13 @@
                M_F("mixer", store_mixer(o, v->value))
                M_F("callerid", store_callerid(o, v->value))
                M_F("boost", store_boost(o, v->value))
+               M_STR("videodevice", o->videodevice)
+               M_UINT("videowidth", o->env.w)
+               M_UINT("videoheight", o->env.h)
 
                M_END(/* */);
        }
+       o->env.videodevice = o->videodevice;
        if (ast_strlen_zero(o->device))
                ast_copy_string(o->device, DEV_DSP, sizeof(o->device));
        if (o->mixer_cmd) {


_______________________________________________
--Bandwidth and Colocation Provided by http://www.api-digital.com--

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to