Index: conf.c
===================================================================
--- conf.c	(revisión: 306)
+++ conf.c	(copia de trabajo)
@@ -53,6 +53,7 @@
 	input:                 IN_DEFAULT,
 	norm:                  0,
 	frame_limit:           DEF_MAXFRAMERATE,
+	discard_frames:        0,
 	quiet:                 1,
 	ppm:                   0,
 	noise:                 DEF_NOISELEVEL,
@@ -267,6 +268,15 @@
 	print_int
 	},
 	{
+	"discard_frames",
+	"# This many frames are discarded for each frame that is read from the camera.\n"
+	"# This is for camera devices that get upset if you don't read all the frames\n"
+	"# they provide, but that provide too many frames.  Default 0 (use all frames).",
+	CONF_OFFSET(discard_frames),
+	copy_int,
+	print_int
+	},
+	{
 	"netcam_url",
 	"# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// or file:///)\n"
 	"# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined",
@@ -533,6 +543,18 @@
 	},
 
 #ifdef HAVE_FFMPEG
+ 	{
+	"ffmpeg_device",
+	"\n############################################################\n"
+	"# Treat device as ffmpeg compliant video stream\n"
+	"############################################################\n\n"
+	"# Setting this flag treats the device specified previously\n"
+	"# as an ffmpeg compliant video stream. This could be a mpeg1,\n"
+	"# mpeg2, mpeg4, divx, xvid, or other compliant video stream.\n",
+	CONF_OFFSET(ffmpeg_device),
+	copy_bool,
+	print_bool
+	},
 	{
 	"ffmpeg_cap_new",
 	"\n############################################################\n"
Index: conf.h
===================================================================
--- conf.h	(revisión: 306)
+++ conf.h	(copia de trabajo)
@@ -36,6 +36,7 @@
 	int input;
 	int norm;
 	int frame_limit;
+	int discard_frames;
 	int quiet;
 	int ppm;
 	int noise;
@@ -54,6 +55,7 @@
 	int pre_capture;
 	int post_capture;
 	int switchfilter;
+	int ffmpeg_device;
 	int ffmpeg_cap_new;
 	int ffmpeg_cap_motion;
 	int ffmpeg_bps;
Index: motion.c
===================================================================
--- motion.c	(revisión: 306)
+++ motion.c	(copia de trabajo)
@@ -850,6 +850,9 @@
 			 */
 			vid_return_code = vid_next(cnt, newimg);
 
+			for (j = 0; j < cnt->conf.discard_frames; j++)
+				vid_return_code = vid_next(cnt, newimg);
+
 			// VALID PICTURE
 			if (vid_return_code == 0) {
 				cnt->lost_connection = 0;
Index: video.h
===================================================================
--- video.h	(revisión: 306)
+++ video.h	(copia de trabajo)
@@ -13,7 +13,10 @@
 #define _LINUX_TIME_H 1
 #ifndef WITHOUT_V4L
 #include <linux/videodev.h>
+#ifdef HAVE_FFMPEG
+#include <ffmpeg/avformat.h>
 #endif
+#endif
 
 /* video4linux stuff */
 #define NORM_DEFAULT    0
@@ -65,8 +68,22 @@
 	int v4l_maxbuffer;
 	int v4l_bufsize;
 #endif
+#ifdef HAVE_FFMPEG
+	AVFormatContext * fcx;
+	AVCodecContext * ccx;
+	AVCodec * codec;
+	AVFormatParameters params;
+	unsigned char *ffmpeg_buffers[2];
+	int ffmpeg_fmt;
+	int ffmpeg_video_index;
+	int ffmpeg_curbuffer;
+	int ffmpeg_maxbuffer;
+	int ffmpeg_bufsize;
+#endif
 };
 
+
+
 /* video functions, video_common.c */
 int vid_start(struct context *);
 int vid_next(struct context *, unsigned char *map);
Index: video_common.c
===================================================================
--- video_common.c	(revisión: 306)
+++ video_common.c	(copia de trabajo)
@@ -582,10 +582,190 @@
 	}
 }
 
+
+#ifdef HAVE_FFMPEG
+static unsigned char *ffmpeg_start(struct context *cnt, struct video_dev *viddev, int input, int norm)
+{
+	int dev=viddev->fd;
+	int err=0;
+	unsigned int i=0, width=0, height=0;
+	viddev->fcx = NULL;
+	viddev->ccx = NULL;
+	viddev->codec = NULL;
+	viddev->ffmpeg_video_index = -1;
+	struct video_channel vid_chnl;
+
+	if (input != IN_DEFAULT) {
+		memset(&vid_chnl, 0, sizeof(struct video_channel));
+		vid_chnl.channel = input;
+		if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) {
+			motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCHAN)");
+		} else {
+			vid_chnl.channel = input;
+			vid_chnl.norm    = norm;
+			if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) {
+				motion_log(LOG_ERR, 1, "ioctl (VIDIOCSCHAN)");
+				return (NULL);
+			}
+		}
+	}
+	// Open the input file.
+	motion_log(LOG_DEBUG, 0, "Openning ffmpeg video stream device: %s", viddev->video_device);
+	err = av_open_input_file(&viddev->fcx, viddev->video_device, NULL, 0, &viddev->params);
+	if (err < 0) {
+		motion_log(LOG_ERR, 1, "Fatal: Can't open video device (%s) using ffmpeg", viddev->video_device);
+		motion_log(LOG_ERR, 1, "Motion Exits");
+		exit(-1);
+	}
+
+	// Find the stream info.
+	err = av_find_stream_info(viddev->fcx);
+	if (err < 0) {
+ 		motion_log(LOG_ERR, 0, "Fatal: Could not locate ffmpeg stream info.");
+ 		motion_log(LOG_ERR, 1, "Motion Exits");
+ 		exit(-1);
+ 	}
+
+		// Find the first video stream.
+ 	motion_log(LOG_DEBUG, 0, "Found %d ffmpeg streams.", viddev->fcx->nb_streams);
+ 	for (i=0; i < viddev->fcx->nb_streams; i++) {
+		viddev->ccx=viddev->fcx->streams[i]->codec;
+		if( viddev->ccx->codec_type == CODEC_TYPE_VIDEO ) 
+			break;
+ 	}
+ 	viddev->ffmpeg_video_index = i;
+ 	motion_log(LOG_DEBUG, 0, "Obtained ffmpeg video_index (%d).", viddev->ffmpeg_video_index);
+
+    
+	// Open stream.
+ 	if (viddev->ffmpeg_video_index >= 0) {
+		viddev->codec = avcodec_find_decoder(viddev->ccx->codec_id);
+		if (viddev->codec)
+ 			err = avcodec_open(viddev->ccx, viddev->codec);
+		if (err < 0) {
+ 			motion_log(LOG_ERR, 1, "Fatal: Can't open ffmpeg codec");
+ 			motion_log(LOG_ERR, 1, "Motion Exits");
+     			av_close_input_file(viddev->fcx);
+ 			exit(-1); 
+ 		} else {
+ 			motion_log(LOG_DEBUG, 0, "Found ffmpeg video stream codec: %s", viddev->codec->name);
+ 		}
+ 	} else {
+ 		motion_log(LOG_ERR, 1, "Fatal: ffmpeg video stream not found");
+ 		motion_log(LOG_ERR, 1, "Motion Exits");
+     		av_close_input_file(viddev->fcx);
+ 		exit(-1);
+ 	}
+ 	width = viddev->ccx->width;
+ 	height = viddev->ccx->height;
+ 	motion_log(LOG_DEBUG, 0, "Size of image: %d x %d x 3/2 = %d.", width, height, (width*height*3)/2);
+ 	viddev->ffmpeg_fmt=VIDEO_PALETTE_YUV420P;
+	viddev->ffmpeg_bufsize=(width*height*3)/2;
+  	viddev->ffmpeg_maxbuffer=1;
+  	viddev->ffmpeg_curbuffer=0;
+  	viddev->ffmpeg_buffers[0]=mymalloc((width*height*3)/2);
+  	viddev->ffmpeg_buffers[1]=mymalloc((width*height*3)/2);
+
+	return viddev->ffmpeg_buffers[0];
+}
+
+static int ffmpeg_next(struct video_dev *viddev, unsigned char *map)
+{
+	int len1=0, got_picture=0;
+	unsigned char *cap_map;
+	AVPicture av_pict;
+	AVPacket av_pkt;
+	AVFrame *av_frame=avcodec_alloc_frame();
+
+	int curbuf = 0, err = 0;
+	
+	viddev->ffmpeg_curbuffer++;
+	if (viddev->ffmpeg_curbuffer > viddev->ffmpeg_maxbuffer)
+		viddev->ffmpeg_curbuffer=0;
+	curbuf=viddev->ffmpeg_curbuffer;
+	cap_map=viddev->ffmpeg_buffers[curbuf];
+	
+	while(!got_picture) {
+		if(!viddev->fcx) {
+			motion_log(LOG_ERR, 0, "NULL pointer for AVFrameContext viddev->fcx.");
+			motion_log(LOG_ERR, 0, "Motion Exits");
+			exit(-1);
+		}
+		err = av_read_frame(viddev->fcx, &av_pkt);
+		switch(err) {
+			case AVERROR_UNKNOWN:
+				motion_log(LOG_ERR, 1, "Unknown error or Invalid data reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			case AVERROR_IO:
+				motion_log(LOG_ERR, 1, "IO error reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			case AVERROR_NUMEXPECTED:
+				motion_log(LOG_ERR, 1, "Number syntax expected in file name while reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			case AVERROR_NOMEM:
+				motion_log(LOG_ERR, 1, "Out of memory while reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			case AVERROR_NOFMT:
+				motion_log(LOG_ERR, 1, "Unkown format while reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			case AVERROR_NOTSUPP:
+				motion_log(LOG_ERR, 1, "Operation not supported while reading AVFrame");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+				break;
+			default:
+				break;
+		}
+		if (av_pkt.stream_index==viddev->ffmpeg_video_index) {
+			if(!viddev->ccx) {
+				motion_log(LOG_ERR, 0, "NULL pointer for AVCodecContext viddev->ccx.");
+				motion_log(LOG_ERR, 0, "Motion Exits");
+				exit(-1);
+			}
+			len1 = avcodec_decode_video(viddev->ccx, av_frame, &got_picture, av_pkt.data, av_pkt.size);
+		}
+	}
+	if (got_picture) {
+		avpicture_alloc(&av_pict, PIX_FMT_YUV420P, viddev->ccx->width, viddev->ccx->height);
+
+		img_convert(&av_pict, PIX_FMT_YUV420P, (AVPicture*) av_frame, viddev->ccx->pix_fmt, viddev->ccx->width, viddev->ccx->height);
+		memset(map, 0, (viddev->ccx->width*viddev->ccx->height*3)/2);
+		memcpy(map, av_pict.data[0], (viddev->ccx->width*viddev->ccx->height*3)/2);
+	} else {
+		motion_log(LOG_WARNING, 0, "Fatal: Unable to decode video packets into frame.");
+		exit(-1);
+	}
+
+        av_free_packet(&av_pkt);
+	
+        // Clean up
+        avpicture_free(&av_pict);
+        av_free(av_frame);
+	// FIXME: This should be closed before exiting motion
+    	// av_close_input_file(av_fcx);
+
+	return 0;
+}
+
+#endif
+
+
+
+
 /**
  * vid_start
  *
- * vid_start setup the capture device. This will be either a V4L device or a netcam.
+ * vid_start setup the capture device. This will be either a V4L device, a netcam or an mpeg stream.
  * The function does the following:
  * - If the camera is a netcam - netcam_start is called and function returns
  * - Width and height are checked for valid value (multiple of 16)
@@ -593,7 +773,7 @@
  *   only copied to the from the conf struct to the imgs struct during program startup
  *   The width and height can no later be changed via http remote control as this would
  *   require major re-memory allocations of all image buffers.
- * - Setup basic V4L properties incl palette incl setting 
+ * - Setup basic V4L or ffmpeg stream properties incl palette incl setting  
  * - Open the device
  * - Returns the device number.
  *
@@ -778,10 +958,104 @@
 {
 	struct config *conf = &cnt->conf;
 	int dev = -1;
+	int i=-1, width=0, height=0, input=0, norm=0;
 
 	if (conf->netcam_url) {
 		return netcam_start(cnt);
 	}
+
+#ifdef HAVE_FFMPEG
+	if (conf->ffmpeg_device) {
+
+		if (conf->width % 16) {
+			motion_log(LOG_ERR, 0,"config image width (%d) is not modulo 16", conf->width);
+			return -1;
+		}
+		if (conf->height % 16) {
+			motion_log(LOG_ERR, 0,"config image height (%d) is not modulo 16", conf->height);
+			return -1;
+		}
+
+		cnt->imgs.width=conf->width;
+		cnt->imgs.height=conf->height;
+		input = conf->input;
+		norm = conf->norm;
+		pthread_mutex_lock(&vid_mutex);
+		while (viddevs[++i]) {
+			if (!strcmp(conf->video_device, viddevs[i]->video_device)) {
+				int fd;
+				cnt->imgs.type=viddevs[i]->ffmpeg_fmt;
+				switch (cnt->imgs.type) {
+					case VIDEO_PALETTE_GREY:
+						cnt->imgs.motionsize=width*height;
+						cnt->imgs.size=width*height;
+						break;
+					case VIDEO_PALETTE_RGB24:
+					case VIDEO_PALETTE_YUV422:
+						cnt->imgs.type=VIDEO_PALETTE_YUV420P;
+					case VIDEO_PALETTE_YUV420P:
+						cnt->imgs.motionsize=width*height;
+						cnt->imgs.size=(width*height*3)/2;
+						break;
+				}
+				fd=viddevs[i]->fd;
+				pthread_mutex_unlock(&vid_mutex);
+				motion_log(LOG_DEBUG, 0, "Found viddev %d using image size of %d.", i, cnt->imgs.size);
+				return fd;
+			}
+		}
+		viddevs=myrealloc(viddevs, sizeof(struct video_dev *)*(i+2), "vid_start");
+		viddevs[i]=mymalloc(sizeof(struct video_dev));
+		memset(viddevs[i], 0, sizeof(struct video_dev));
+		viddevs[i+1]=NULL;
+
+		pthread_mutexattr_init(&viddevs[i]->attr);
+		pthread_mutex_init(&viddevs[i]->mutex, NULL);
+
+		dev=open(conf->video_device, O_RDWR);
+		if (dev <0) {
+			motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device);
+			motion_log(LOG_ERR, 0, "Motion Exits");
+			exit(1);
+ 		}
+		viddevs[i]->fd = dev;
+		viddevs[i]->brightness=0;
+		viddevs[i]->contrast=0;
+		viddevs[i]->saturation=0;
+		viddevs[i]->hue=0;
+		viddevs[i]->owner=-1;	
+		viddevs[i]->ffmpeg_fmt=VIDEO_PALETTE_YUV420P;
+		viddevs[i]->video_device = conf->video_device;
+
+		if(!ffmpeg_start(cnt, viddevs[i], input, norm)) {
+			motion_log(LOG_DEBUG, 0, "Failed in ffmpeg_start.");
+			pthread_mutex_unlock(&vid_mutex);
+ 			return -1;
+ 		}
+		cnt->imgs.type=viddevs[i]->ffmpeg_fmt;
+		width = viddevs[i]->ccx->width;
+		height = viddevs[i]->ccx->height;
+		cnt->imgs.width=width;
+		cnt->imgs.height=height;
+		switch (cnt->imgs.type) {
+			case VIDEO_PALETTE_GREY:
+				cnt->imgs.size=width*height;
+				cnt->imgs.motionsize=width*height;
+			break;
+			case VIDEO_PALETTE_RGB24:
+			case VIDEO_PALETTE_YUV422:
+				cnt->imgs.type=VIDEO_PALETTE_YUV420P;
+			case VIDEO_PALETTE_YUV420P:
+				cnt->imgs.size=(width*height*3)/2;
+				cnt->imgs.motionsize=width*height;
+			break;
+		}
+		pthread_mutex_unlock(&vid_mutex);
+		motion_log(LOG_DEBUG, 0, "Started ffmpeg stream with image size of %d and motionsize %d.", cnt->imgs.size, cnt->imgs.motionsize);
+		return dev;
+	}
+#endif
+
 #ifndef WITHOUT_V4L
 	dev = vid_v4lx_start(cnt);
 #endif				/*WITHOUT_V4L */
@@ -821,6 +1095,38 @@
 		ret = netcam_next(cnt, map);
 		return ret;
 	}
+
+#ifdef HAVE_FFMPEG
+	if(conf->ffmpeg_device) {
+		int i = -1;
+		int dev = cnt->video_dev;
+
+		while (viddevs[++i])
+			if (viddevs[i]->fd==dev)
+				break;
+
+		if (!viddevs[i])
+			return -1;
+
+		if (viddevs[i]->owner != cnt->threadnr) {
+			pthread_mutex_lock(&viddevs[i]->mutex);
+			viddevs[i]->owner = cnt->threadnr;
+			viddevs[i]->frames = conf->roundrobin_frames;
+			cnt->switched = 1;
+		}
+		map = ffmpeg_next(viddevs[i], map);
+		if (--viddevs[i]->frames <= 0) {
+			viddevs[i]->owner = -1;
+			pthread_mutex_unlock(&viddevs[i]->mutex);
+		}
+		if(cnt->rotate_data.degrees > 0) {
+			/* rotate the image as specified */
+			rotate_map(cnt, map);
+		}
+		return (int)map;
+	}
+#endif
+
 #ifndef WITHOUT_V4L
 
 	/* We start a new block so we can make declarations without breaking
Index: motion-dist.conf
===================================================================
--- motion-dist.conf	(revisión: 306)
+++ motion-dist.conf	(copia de trabajo)
@@ -57,6 +57,13 @@
 # Valid range: 2-100. Default: 100 (almost no limit).
 framerate 2
 
+# Number of frames to discard for each frame captured.  This is
+# useful for devices that get upset if you are reading frames
+# too slowly.  One example is the ivtv driver (Hauppauge Win-TV
+# cards).
+# default: 0
+discard_frames 0
+
 # Minimum time in seconds between capturing picture frames from the camera.
 # Default: 0 = disabled - the capture rate is given by the camera framerate.
 # This option is used when you want to capture images at a rate lower than 2 per second.
@@ -256,6 +263,11 @@
 # (default: off)
 ffmpeg_deinterlace off
 
+# Use ffmpeg to decode the data from the camera.  Necessary if your
+# data source delivers data in a format that ffmpeg understands (eg
+# mpeg2 as delivered by ivtv cards).
+# (default: off)
+ffmpeg_device off
 
 ############################################################
 # Snapshots (Traditional Periodic Webcam File Output)
