[asterisk-commits] rizzo: branch rizzo/astobj2 r77314 - /team/rizzo/astobj2/channels/chan_oss.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jul 26 11:34:56 CDT 2007
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) {
More information about the asterisk-commits
mailing list