[MPlayer-dev-eng] [PATCH] support for hardware mjpeg encoding in tvi_v4l.c

Ivan Szanto szivan at duticai.TWI.TUDelft.NL
Tue Mar 11 23:31:46 CET 2003


Hi,


I have a Matrox Marvel card, and "mplayer -tv on ..." gives me
no good quality pictures, because when I set it to a decent resolution
(at least 352x288), it drops many frames. And this is not due to CPU
limitations, but the reason is that the current code in tvi_v4l.c
does not use hardware mjpeg encoding.

It is the goal of the attached patch to overcome this limitation.
I added the option "mjpeg" to the list of -tv options, which
is used to switch on hardware mjpeg encoding. It works for me.
Without this option the code does everything like it did before
(I mean it does not break anything).

Changes:

1. cfg-common.h        for the new options
2. DOCS/en/mplayer.1   for explaining the new options

all the rest is in the libmpdemux directory.

3. tv.h and tv.c for the new options
4. tvi_v4l.c for the implementation

and then I added a couple of files (borrowed from mjpegtools):

5. videodev_mjpeg.h for the constants neccessary for the ioctl's
6. jpegutils.c - I used "decode_jpeg_raw" from this file to
                 take each jpeg encoded by the hardware encoder
                 and to decode it to YUV420 format.
   This takes a lot of CPU power, and there ought to exist a
   better method. Please let me know about that better method.
   Even better, please fix the code with that better method.
   But I'm willing to do the fix, just please let me know.
7. the rest of the files are necessary for jpegutils.c:
   jpegutils.h, lav_io.h, mjpeg_logging.c, mjpeg_logging.h,
   mjpeg_types.h


Please let me know if anything is wrong with it. Thanx.

Ivan
-------------- next part --------------
diff -Naur main/DOCS/en/mplayer.1 main-mjpeg/DOCS/en/mplayer.1
--- main/DOCS/en/mplayer.1	Sun Mar  9 18:15:16 2003
+++ main-mjpeg/DOCS/en/mplayer.1	Tue Mar 11 22:55:00 2003
@@ -787,6 +787,23 @@
 (default for mencoder).
 A value of 1 (default for mplayer) means to do video capture only and let the
 audio go through a loopback cable from the TV card to the soundcard.
+.IPs mjpeg
+Use hardware mjpeg compression (if the card supports it). 
+When using this option, you do not need to specify the width and height
+of the output window, because mplayer will determine it automatically 
+from the decimation value (see below).
+.IPs decimation
+choose the size of the picture that will be compressed by hardware
+mjpeg compression:
+.RSss
+1: big size: 704x576
+.br
+2: medium size: 352x288
+.br
+4: small size: 176x144 
+.REss
+.IPs quality
+choose the quality of the jpeg compression [0-99] (useful for big size)
 .RE
 .
 .TP
diff -Naur main/cfg-common.h main-mjpeg/cfg-common.h
--- main/cfg-common.h	Wed Mar  5 10:19:54 2003
+++ main-mjpeg/cfg-common.h	Tue Mar 11 23:03:46 2003
@@ -279,6 +279,10 @@
 	{"forcechan", &tv_param_forcechan, CONF_TYPE_INT, CONF_RANGE, 1, 2, NULL},
 	{"forceaudio", &tv_param_force_audio, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 	{"buffersize", &tv_param_buffer_size, CONF_TYPE_INT, CONF_RANGE, 16, 1024, NULL},
+	{"mjpeg", &tv_param_mjpeg, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"decimation", &tv_param_decimation, CONF_TYPE_INT, CONF_RANGE, 1, 4, NULL},
+	{"quality", &tv_param_quality, CONF_TYPE_INT, CONF_RANGE, 1, 99, NULL},
+	{"interlace", &tv_param_interlace, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
 #ifdef HAVE_ALSA9
 	{"alsa", &tv_param_alsa, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 #endif
diff -Naur main/libmpdemux/Makefile main-mjpeg/libmpdemux/Makefile
--- main/libmpdemux/Makefile	Mon Feb  3 10:27:50 2003
+++ main-mjpeg/libmpdemux/Makefile	Tue Mar 11 22:55:00 2003
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c jpegutils.c mjpeg_logging.c
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
diff -Naur main/libmpdemux/jpegutils.c main-mjpeg/libmpdemux/jpegutils.c
--- main/libmpdemux/jpegutils.c	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/jpegutils.c	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,811 @@
+/*
+ *  jpegutils.c: Some Utility programs for dealing with
+ *               JPEG encoded images
+ *
+ *  Copyright (C) 1999 Rainer Johanni <Rainer at Johanni.de>
+ *  Copyright (C) 2001 pHilipp Zabel  <pzabel at gmx.de>
+ *
+ *  based on jdatasrc.c and jdatadst.c from the Independent
+ *  JPEG Group's software by Thomas G. Lane
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <jpeglib.h>
+#include <jerror.h>
+
+#include "mjpeg_logging.h"
+
+#include "jpegutils.h"
+#include "lav_io.h"
+
+ /*
+ * jpeg_data:       buffer with input / output jpeg
+ * len:             Length of jpeg buffer
+ * itype:           0: Not interlaced
+ *                  1: Interlaced, Top field first
+ *                  2: Interlaced, Bottom field first
+ * ctype            Chroma format for decompression.
+ *                  Currently always 420 and hence ignored.
+ * raw0             buffer with input / output raw Y channel
+ * raw1             buffer with input / output raw U/Cb channel
+ * raw2             buffer with input / output raw V/Cr channel
+ * width            width of Y channel (width of U/V is width/2)
+ * height           height of Y channel (height of U/V is height/2)
+ */
+
+
+static void jpeg_buffer_src  (j_decompress_ptr cinfo, unsigned char *buffer,
+                       long num);
+static void jpeg_buffer_dest (j_compress_ptr cinfo,   unsigned char *buffer,
+                       long len);
+static void jpeg_skip_ff (j_decompress_ptr cinfo);
+
+/*******************************************************************
+ *                                                                 *
+ *    The following routines define a JPEG Source manager which    *
+ *    just reads from a given buffer (instead of a file as in      *
+ *    the jpeg library)                                            *
+ *                                                                 *
+ *******************************************************************/
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+static void init_source (j_decompress_ptr cinfo)
+{
+   /* no work necessary here */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * Should never be called since all data should be allready provided.
+ * Is nevertheless sometimes called - sets the input buffer to data
+ * which is the JPEG EOI marker;
+ *
+ */
+
+static uint8_t EOI_data[2] = { 0xFF, 0xD9 };
+
+static boolean fill_input_buffer (j_decompress_ptr cinfo)
+{
+   cinfo->src->next_input_byte = EOI_data;
+   cinfo->src->bytes_in_buffer = 2;
+   return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ */
+
+static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+   if (num_bytes > 0) {
+      if (num_bytes > (long) cinfo->src->bytes_in_buffer)
+         num_bytes = (long) cinfo->src->bytes_in_buffer;
+      cinfo->src->next_input_byte += (size_t) num_bytes;
+      cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
+   }
+}
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read.  Often a no-op.
+ */
+
+static void term_source (j_decompress_ptr cinfo)
+{
+   /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a data buffer.
+ */
+
+static void
+jpeg_buffer_src (j_decompress_ptr cinfo, unsigned char *buffer, long num)
+{
+   /* The source object and input buffer are made permanent so that a series
+    * of JPEG images can be read from the same buffer by calling jpeg_buffer_src
+    * only before the first one.  (If we discarded the buffer at the end of
+    * one image, we'd likely lose the start of the next one.)
+    * This makes it unsafe to use this manager and a different source
+    * manager serially with the same JPEG object.  Caveat programmer.
+    */
+   if (cinfo->src == NULL) {    /* first time for this JPEG object? */
+      cinfo->src = (struct jpeg_source_mgr *)
+          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                      sizeof (struct jpeg_source_mgr));
+   }
+
+   cinfo->src->init_source = init_source;
+   cinfo->src->fill_input_buffer = fill_input_buffer;
+   cinfo->src->skip_input_data = skip_input_data;
+   cinfo->src->resync_to_restart = jpeg_resync_to_restart;	/* use default method */
+   cinfo->src->term_source = term_source;
+   cinfo->src->bytes_in_buffer = num;
+   cinfo->src->next_input_byte = (JOCTET *) buffer;
+}
+
+
+/*
+ * jpeg_skip_ff is not a part of the source manager but it is
+ * particularly useful when reading several images from the same buffer:
+ * It should be called to skip padding 0xff bytes beetween images.
+ */
+
+static void 
+jpeg_skip_ff (j_decompress_ptr cinfo)
+{
+   while (cinfo->src->bytes_in_buffer > 1
+          && cinfo->src->next_input_byte[0] == 0xff
+          && cinfo->src->next_input_byte[1] == 0xff) {
+      cinfo->src->bytes_in_buffer--;
+      cinfo->src->next_input_byte++;
+   }
+}
+
+
+/*******************************************************************
+ *                                                                 *
+ *    The following routines define a JPEG Destination manager     *
+ *    which just reads from a given buffer (instead of a file      *
+ *    as in the jpeg library)                                      *
+ *                                                                 *
+ *******************************************************************/
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+static void init_destination (j_compress_ptr cinfo)
+{
+   /* No work necessary here */
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * Should never be called since all data should be written to the buffer.
+ * If it gets called, the given jpeg buffer was too small.
+ *
+ */
+
+static boolean empty_output_buffer (j_compress_ptr cinfo)
+{
+   /*FIXME: */
+   mjpeg_error( "Given jpeg buffer was too small!");
+   ERREXIT (cinfo, JERR_BUFFER_SIZE);	/* shouldn't be FILE_WRITE but BUFFER_OVERRUN! */
+   return TRUE;
+}
+
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written.  Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+static void term_destination (j_compress_ptr cinfo)
+{
+   /* no work necessary here */
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+static void
+jpeg_buffer_dest (j_compress_ptr cinfo, unsigned char *buf, long len)
+{
+
+   /* The destination object is made permanent so that multiple JPEG images
+    * can be written to the same file without re-executing jpeg_stdio_dest.
+    * This makes it dangerous to use this manager and a different destination
+    * manager serially with the same JPEG object, because their private object
+    * sizes may be different.  Caveat programmer.
+    */
+   if (cinfo->dest == NULL) {   /* first time for this JPEG object? */
+      cinfo->dest = (struct jpeg_destination_mgr *)
+          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                      sizeof (struct
+                                              jpeg_destination_mgr));
+   }
+
+   cinfo->dest->init_destination = init_destination;
+   cinfo->dest->empty_output_buffer = empty_output_buffer;
+   cinfo->dest->term_destination = term_destination;
+   cinfo->dest->free_in_buffer = len;
+   cinfo->dest->next_output_byte = (JOCTET *) buf;
+}
+
+
+/*******************************************************************
+ *                                                                 *
+ *    decode_jpeg_data: Decode a (possibly interlaced) JPEG frame  *
+ *                                                                 *
+ *******************************************************************/
+
+/*
+ * ERROR HANDLING:
+ *
+ *    We want in all cases to return to the user.
+ *    The following kind of error handling is from the
+ *    example.c file in the Independent JPEG Group's JPEG software
+ */
+
+struct my_error_mgr {
+   struct jpeg_error_mgr pub;   /* "public" fields */
+   jmp_buf setjmp_buffer;       /* for return to caller */
+};
+
+static void my_error_exit (j_common_ptr cinfo)
+{
+   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+   struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
+
+   /* Always display the message. */
+   /* We could postpone this until after returning, if we chose. */
+   (*cinfo->err->output_message) (cinfo);
+
+   /* Return control to the setjmp point */
+   longjmp (myerr->setjmp_buffer, 1);
+}
+
+#define MAX_LUMA_WIDTH   4096
+#define MAX_CHROMA_WIDTH 2048
+
+static unsigned char buf0[16][MAX_LUMA_WIDTH];
+static unsigned char buf1[8][MAX_CHROMA_WIDTH];
+static unsigned char buf2[8][MAX_CHROMA_WIDTH];
+static unsigned char chr1[8][MAX_CHROMA_WIDTH];
+static unsigned char chr2[8][MAX_CHROMA_WIDTH];
+
+
+
+#if 1  /* generation of 'std' Huffman tables... */
+
+static void add_huff_table (j_decompress_ptr dinfo,
+			    JHUFF_TBL **htblptr, 
+			    const UINT8 *bits, const UINT8 *val)
+/* Define a Huffman table */
+{
+  int nsymbols, len;
+
+  if (*htblptr == NULL)
+    *htblptr = jpeg_alloc_huff_table((j_common_ptr) dinfo);
+
+  /* Copy the number-of-symbols-of-each-code-length counts */
+  memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
+
+  /* Validate the counts.  We do this here mainly so we can copy the right
+   * number of symbols from the val[] array, without risking marching off
+   * the end of memory.  jchuff.c will do a more thorough test later.
+   */
+  nsymbols = 0;
+  for (len = 1; len <= 16; len++)
+    nsymbols += bits[len];
+  if (nsymbols < 1 || nsymbols > 256)
+    mjpeg_error_exit1("jpegutils.c:  add_huff_table failed badly. ");
+
+  memcpy((*htblptr)->huffval, val, nsymbols * sizeof(UINT8));
+}
+
+
+
+static void std_huff_tables (j_decompress_ptr dinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+  static const UINT8 bits_dc_luminance[17] =
+    { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_luminance[] =
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  
+  static const UINT8 bits_dc_chrominance[17] =
+    { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+  static const UINT8 val_dc_chrominance[] =
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  
+  static const UINT8 bits_ac_luminance[17] =
+    { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+  static const UINT8 val_ac_luminance[] =
+    { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+      0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+      0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+      0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+      0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+      0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+      0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+      0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+      0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+      0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+      0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+      0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+      0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+      0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+      0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+      0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+      0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+      0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+      0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+      0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+      0xf9, 0xfa };
+  
+  static const UINT8 bits_ac_chrominance[17] =
+    { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+  static const UINT8 val_ac_chrominance[] =
+    { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+      0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+      0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+      0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+      0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+      0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+      0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+      0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+      0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+      0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+      0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+      0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+      0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+      0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+      0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+      0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+      0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+      0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+      0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+      0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+      0xf9, 0xfa };
+  
+  add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[0],
+		 bits_dc_luminance, val_dc_luminance);
+  add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[0],
+		 bits_ac_luminance, val_ac_luminance);
+  add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[1],
+		 bits_dc_chrominance, val_dc_chrominance);
+  add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[1],
+		 bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+
+static void guarantee_huff_tables(j_decompress_ptr dinfo)
+{
+  if ( (dinfo->dc_huff_tbl_ptrs[0] == NULL) &&
+       (dinfo->dc_huff_tbl_ptrs[1] == NULL) &&
+       (dinfo->ac_huff_tbl_ptrs[0] == NULL) &&
+       (dinfo->ac_huff_tbl_ptrs[1] == NULL) ) {
+    mjpeg_debug( "Generating standard Huffman tables for this frame.");
+    std_huff_tables(dinfo);
+  }
+}
+
+
+#endif /* ...'std' Huffman table generation */
+
+
+
+/*
+ * jpeg_data:       Buffer with jpeg data to decode
+ * len:             Length of buffer
+ * itype:           0: Not interlaced
+ *                  1: Interlaced, Top field first
+ *                  2: Interlaced, Bottom field first
+ * ctype            Chroma format for decompression.
+ *                  Currently always 420 and hence ignored.
+ */
+
+int decode_jpeg_raw (unsigned char *jpeg_data, int len,
+                     int itype, int ctype, int width, int height,
+                     unsigned char *raw0, unsigned char *raw1,
+                     unsigned char *raw2)
+{
+   int numfields, hsf[3], vsf[3], field, yl, yc, x, y, i, xsl, xsc, xs, xd,
+       hdown;
+
+   JSAMPROW row0[16] = { buf0[0], buf0[1], buf0[2], buf0[3],
+      buf0[4], buf0[5], buf0[6], buf0[7],
+      buf0[8], buf0[9], buf0[10], buf0[11],
+      buf0[12], buf0[13], buf0[14], buf0[15]
+   };
+   JSAMPROW row1[8] = { buf1[0], buf1[1], buf1[2], buf1[3],
+      buf1[4], buf1[5], buf1[6], buf1[7]
+   };
+   JSAMPROW row2[8] = { buf2[0], buf2[1], buf2[2], buf2[3],
+      buf2[4], buf2[5], buf2[6], buf2[7]
+   };
+   JSAMPARRAY scanarray[3] = { row0, row1, row2 };
+   struct jpeg_decompress_struct dinfo;
+   struct my_error_mgr jerr;
+
+   /* We set up the normal JPEG error routines, then override error_exit. */
+   dinfo.err = jpeg_std_error (&jerr.pub);
+   jerr.pub.error_exit = my_error_exit;
+
+   /* Establish the setjmp return context for my_error_exit to use. */
+   if (setjmp (jerr.setjmp_buffer)) {
+      /* If we get here, the JPEG code has signaled an error. */
+      jpeg_destroy_decompress (&dinfo);
+      return -1;
+   }
+
+   jpeg_create_decompress (&dinfo);
+
+   jpeg_buffer_src (&dinfo, jpeg_data, len);
+
+   /* Read header, make some checks and try to figure out what the
+      user really wants */
+
+   jpeg_read_header (&dinfo, TRUE);
+   dinfo.raw_data_out = TRUE;
+   dinfo.out_color_space = JCS_YCbCr;
+   dinfo.dct_method = JDCT_IFAST;
+   guarantee_huff_tables(&dinfo);
+   jpeg_start_decompress (&dinfo);
+
+   if (dinfo.output_components != 3) {
+      mjpeg_error( "Output components of JPEG image = %d, must be 3",
+               dinfo.output_components);
+      goto ERR_EXIT;
+   }
+
+   for (i = 0; i < 3; i++) {
+      hsf[i] = dinfo.comp_info[i].h_samp_factor;
+      vsf[i] = dinfo.comp_info[i].v_samp_factor;
+   }
+
+   if (hsf[0] != 2 || hsf[1] != 1 || hsf[2] != 1 ||
+       (vsf[0] != 1 && vsf[0] != 2) || vsf[1] != 1 || vsf[2] != 1) {
+      mjpeg_error( "Unsupported sampling factors!");
+      goto ERR_EXIT;
+   }
+
+   /* Height match image height or be exact twice the image height */
+
+   if (dinfo.output_height == height) {
+      numfields = 1;
+   } else if (2 * dinfo.output_height == height) {
+      numfields = 2;
+   } else {
+      mjpeg_error(
+               "Read JPEG: requested height = %d, height of image = %d",
+               height, dinfo.output_height);
+      goto ERR_EXIT;
+   }
+
+   /* Width is more flexible */
+
+   if (dinfo.output_width > MAX_LUMA_WIDTH) {
+      mjpeg_error( "Image width of %d exceeds max",
+               dinfo.output_width);
+      goto ERR_EXIT;
+   }
+   if (width < 2 * dinfo.output_width / 3) {
+      /* Downsample 2:1 */
+
+      hdown = 1;
+      if (2 * width < dinfo.output_width)
+         xsl = (dinfo.output_width - 2 * width) / 2;
+      else
+         xsl = 0;
+   } else if (width == 2 * dinfo.output_width / 3) {
+      /* special case of 3:2 downsampling */
+
+      hdown = 2;
+      xsl = 0;
+   } else {
+      /* No downsampling */
+
+      hdown = 0;
+      if (width < dinfo.output_width)
+         xsl = (dinfo.output_width - width) / 2;
+      else
+         xsl = 0;
+   }
+
+   /* Make xsl even, calculate xsc */
+
+   xsl = xsl & ~1;
+   xsc = xsl / 2;
+
+   yl = yc = 0;
+
+   for (field = 0; field < numfields; field++) {
+      if (field > 0) {
+         jpeg_read_header (&dinfo, TRUE);
+         dinfo.raw_data_out = TRUE;
+         dinfo.out_color_space = JCS_YCbCr;
+         dinfo.dct_method = JDCT_IFAST;
+         jpeg_start_decompress (&dinfo);
+      }
+
+      if (numfields == 2) {
+         switch (itype) {
+         case LAV_INTER_TOP_FIRST:
+            yl = yc = field;
+            break;
+         case LAV_INTER_BOTTOM_FIRST:
+            yl = yc = (1 - field);
+            break;
+         default:
+            mjpeg_error(
+                     "Input is interlaced but no interlacing set");
+            goto ERR_EXIT;
+         }
+      } else
+         yl = yc = 0;
+
+      while (dinfo.output_scanline < dinfo.output_height) {
+         jpeg_read_raw_data (&dinfo, scanarray, 8 * vsf[0]);
+
+         for (y = 0; y < 8 * vsf[0]; yl += numfields, y++) {
+            xd = yl * width;
+            xs = xsl;
+
+            if (hdown == 0)
+               for (x = 0; x < width; x++)
+                  raw0[xd++] = row0[y][xs++];
+            else if (hdown == 1)
+               for (x = 0; x < width; x++, xs += 2)
+                  raw0[xd++] = (row0[y][xs] + row0[y][xs + 1]) >> 1;
+            else
+               for (x = 0; x < width / 2; x++, xd += 2, xs += 3) {
+                  raw0[xd] = (2 * row0[y][xs] + row0[y][xs + 1]) / 3;
+                  raw0[xd + 1] =
+                      (2 * row0[y][xs + 2] + row0[y][xs + 1]) / 3;
+               }
+         }
+
+         /* Horizontal downsampling of chroma */
+
+         for (y = 0; y < 8; y++) {
+            xs = xsc;
+
+            if (hdown == 0)
+               for (x = 0; x < width / 2; x++, xs++) {
+                  chr1[y][x] = row1[y][xs];
+                  chr2[y][x] = row2[y][xs];
+            } else if (hdown == 1)
+               for (x = 0; x < width / 2; x++, xs += 2) {
+                  chr1[y][x] = (row1[y][xs] + row1[y][xs + 1]) >> 1;
+                  chr2[y][x] = (row2[y][xs] + row2[y][xs + 1]) >> 1;
+            } else
+               for (x = 0; x < width / 2; x += 2, xs += 3) {
+                  chr1[y][x] = (2 * row1[y][xs] + row1[y][xs + 1]) / 3;
+                  chr1[y][x + 1] =
+                      (2 * row1[y][xs + 2] + row1[y][xs + 1]) / 3;
+                  chr2[y][x] = (2 * row2[y][xs] + row2[y][xs + 1]) / 3;
+                  chr2[y][x + 1] =
+                      (2 * row2[y][xs + 2] + row2[y][xs + 1]) / 3;
+               }
+         }
+
+         /* Vertical downsampling of chroma */
+
+         if (vsf[0] == 1) {
+            /* Really downsample */
+
+            for (y = 0; y < 8; y += 2, yc += numfields) {
+               xd = yc * width / 2;
+               for (x = 0; x < width / 2; x++, xd++) {
+                  raw1[xd] = (chr1[y][x] + chr1[y + 1][x]) >> 1;
+                  raw2[xd] = (chr2[y][x] + chr2[y + 1][x]) >> 1;
+               }
+            }
+         } else {
+            /* Just copy */
+
+            for (y = 0; y < 8; y++, yc += numfields) {
+               xd = yc * width / 2;
+               for (x = 0; x < width / 2; x++, xd++) {
+                  raw1[xd] = chr1[y][x];
+                  raw2[xd] = chr2[y][x];
+               }
+            }
+         }
+      }
+
+      (void) jpeg_finish_decompress (&dinfo);
+      if (field == 0 && numfields > 1)
+         jpeg_skip_ff (&dinfo);
+   }
+
+   jpeg_destroy_decompress (&dinfo);
+   return 0;
+
+ ERR_EXIT:
+   jpeg_destroy_decompress (&dinfo);
+   return -1;
+}
+
+
+/*******************************************************************
+ *                                                                 *
+ *    encode_jpeg_data: Compress raw YCbCr data (output JPEG       *
+ *                      may be interlaced                          *
+ *                                                                 *
+ *******************************************************************/
+ 
+ /*
+ * jpeg_data:       Buffer to hold output jpeg
+ * len:             Length of buffer
+ * itype:           0: Not interlaced
+ *                  1: Interlaced, Top field first
+ *                  2: Interlaced, Bottom field first
+ * ctype            Chroma format for decompression.
+ *                  Currently always 420 and hence ignored.
+ */
+
+int encode_jpeg_raw (unsigned char *jpeg_data, int len, int quality,
+                     int itype, int ctype, int width, int height,
+                     unsigned char *raw0, unsigned char *raw1,
+                     unsigned char *raw2)
+{
+   int numfields, field, yl, yc, y, i;
+
+   JSAMPROW row0[16] = { buf0[0], buf0[1], buf0[2], buf0[3],
+      buf0[4], buf0[5], buf0[6], buf0[7],
+      buf0[8], buf0[9], buf0[10], buf0[11],
+      buf0[12], buf0[13], buf0[14], buf0[15]
+   };
+   JSAMPROW row1[8] = { buf1[0], buf1[1], buf1[2], buf1[3],
+      buf1[4], buf1[5], buf1[6], buf1[7]
+   };
+   JSAMPROW row2[8] = { buf2[0], buf2[1], buf2[2], buf2[3],
+      buf2[4], buf2[5], buf2[6], buf2[7]
+   };
+   JSAMPARRAY scanarray[3] = { row0, row1, row2 };
+
+   struct jpeg_compress_struct cinfo;
+   struct my_error_mgr jerr;
+
+   /* We set up the normal JPEG error routines, then override error_exit. */
+   cinfo.err = jpeg_std_error (&jerr.pub);
+   jerr.pub.error_exit = my_error_exit;
+
+   /* Establish the setjmp return context for my_error_exit to use. */
+   if (setjmp (jerr.setjmp_buffer)) {
+      /* If we get here, the JPEG code has signaled an error. */
+      jpeg_destroy_compress (&cinfo);
+      return -1;
+   }
+
+   jpeg_create_compress (&cinfo);
+
+   jpeg_buffer_dest(&cinfo, jpeg_data, len);
+
+   /* Set some jpeg header fields */
+
+   cinfo.input_components = 3;
+   jpeg_set_defaults (&cinfo);
+   jpeg_set_quality  (&cinfo, quality, FALSE);
+
+   cinfo.raw_data_in = TRUE;
+   cinfo.in_color_space = JCS_YCbCr;
+   cinfo.dct_method = JDCT_IFAST;
+
+   cinfo.input_gamma = 1.0;
+
+   cinfo.comp_info[0].h_samp_factor = 2;
+   cinfo.comp_info[0].v_samp_factor = 1;	/*1||2 */
+   cinfo.comp_info[1].h_samp_factor = 1;
+   cinfo.comp_info[1].v_samp_factor = 1;
+   cinfo.comp_info[2].h_samp_factor = 1;	/*1||2 */
+   cinfo.comp_info[2].v_samp_factor = 1;
+
+
+   if ((width>4096)||(height>4096)) {
+      mjpeg_error( "Image dimensions (%dx%d) exceed lavtools' max (4096x4096)", width, height);
+      goto ERR_EXIT;
+   }
+   if ((width%16)||(height%16)) {
+      mjpeg_error( "Image dimensions (%dx%d) not multiples of 16", width, height);
+      goto ERR_EXIT;
+   }
+   cinfo.image_width = width;
+   switch (itype) {
+   case LAV_INTER_TOP_FIRST:
+   case LAV_INTER_BOTTOM_FIRST: /* interlaced */
+      numfields = 2;
+      break;
+   default:
+      numfields = 1;
+      if (height > 2048) {
+         mjpeg_error( "Image height (%d) exceeds lavtools max for non-interlaced frames", height);
+         goto ERR_EXIT;
+      }
+   }
+   cinfo.image_height = height/numfields;
+
+   yl = yc = 0;                 /* y luma, chroma */
+
+   for (field = 0; field < numfields; field++) {
+
+      jpeg_start_compress (&cinfo, FALSE);
+      
+      if (numfields == 2) {
+         static const JOCTET marker0[40];
+
+	 jpeg_write_marker(&cinfo, JPEG_APP0,   marker0, 14);
+	 jpeg_write_marker(&cinfo, JPEG_APP0+1, marker0, 40);
+
+         switch (itype) {
+         case LAV_INTER_TOP_FIRST: /* top field first */
+            yl = yc = field;
+            break;
+         case LAV_INTER_BOTTOM_FIRST: /* bottom field first */
+            yl = yc = (1 - field);
+            break;
+         default:
+            mjpeg_error(
+                     "Input is interlaced but no interlacing set");
+            goto ERR_EXIT;
+         }
+      } else
+         yl = yc = 0;
+
+      while (cinfo.next_scanline < cinfo.image_height) {
+
+         for (y = 0; y < 8 * cinfo.comp_info[0].v_samp_factor;
+              yl += numfields, y++) {
+            row0[y] = &raw0[yl * width];
+         }
+         for (y = 0; y < 8; y++) {
+            row1[y] = &raw1[yc * width / 2];
+            row2[y] = &raw2[yc * width / 2];
+            if (y%2) yc += numfields;
+         }
+
+         jpeg_write_raw_data (&cinfo, scanarray,
+                              8 * cinfo.comp_info[0].v_samp_factor);
+
+      }
+
+      (void) jpeg_finish_compress (&cinfo);
+   }
+   
+   /* FIXME */
+   i = len - cinfo.dest->free_in_buffer;
+
+   jpeg_destroy_compress (&cinfo);
+
+   return i;   /* size of jpeg */
+
+ ERR_EXIT:
+   jpeg_destroy_compress (&cinfo);
+   return -1;
+}
diff -Naur main/libmpdemux/jpegutils.h main-mjpeg/libmpdemux/jpegutils.h
--- main/libmpdemux/jpegutils.h	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/jpegutils.h	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,55 @@
+/*
+ *  jpegutils.h: Some Utility programs for dealing with
+ *               JPEG encoded images
+ *
+ *  Copyright (C) 1999 Rainer Johanni <Rainer at Johanni.de>
+ *  Copyright (C) 2001 pHilipp Zabel  <pzabel at gmx.de>
+ *
+ *  based on jdatasrc.c and jdatadst.c from the Independent
+ *  JPEG Group's software by Thomas G. Lane
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#ifndef __JPEGUTILS_H__
+#define __JPEGUTILS_H__
+
+ /*
+ * jpeg_data:       buffer with input / output jpeg
+ * len:             Length of jpeg buffer
+ * itype:           LAV_INTER_NONE: Not interlaced
+ *                  LAV_INTER_TOP_FIRST: Interlaced, top-field-first
+ *                  LAV_INTER_BOTTOM_FIRST: Interlaced, bottom-field-first
+ * ctype            Chroma format for decompression.
+ *                  Currently always 420 and hence ignored.
+ * raw0             buffer with input / output raw Y channel
+ * raw1             buffer with input / output raw U/Cb channel
+ * raw2             buffer with input / output raw V/Cr channel
+ * width            width of Y channel (width of U/V is width/2)
+ * height           height of Y channel (height of U/V is height/2)
+ */
+
+int decode_jpeg_raw (unsigned char *jpeg_data, int len,
+                     int itype, int ctype, int width, int height,
+                     unsigned char *raw0, unsigned char *raw1,
+                     unsigned char *raw2);
+
+int encode_jpeg_raw (unsigned char *jpeg_data, int len, int quality,
+                     int itype, int ctype, int width, int height,
+                     unsigned char *raw0, unsigned char *raw1,
+                     unsigned char *raw2);
+/*
+void jpeg_skip_ff   (j_decompress_ptr cinfo);
+*/
+#endif
diff -Naur main/libmpdemux/lav_io.h main-mjpeg/libmpdemux/lav_io.h
--- main/libmpdemux/lav_io.h	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/lav_io.h	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,115 @@
+/*
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LAV_IO_H
+
+#define LAV_IO_H
+
+#ifdef COMPILE_LAV_IO_C
+#include <avilib.h>
+
+#ifdef HAVE_LIBQUICKTIME
+#ifdef HAVE_OPENQUICKTIME
+#include <openquicktime.h>
+#else
+#include <quicktime.h>
+#endif
+#endif
+
+#ifdef HAVE_LIBMOVTAR
+#include <movtar.h>
+#endif
+#else
+typedef void avi_t;
+typedef void quicktime_t;
+typedef void movtar_t;
+#endif
+
+#include "yuv4mpeg.h"
+
+#define LAV_INTER_UNKNOWN       Y4M_UNKNOWN
+#define LAV_NOT_INTERLACED      Y4M_ILACE_NONE
+#define LAV_INTER_TOP_FIRST     Y4M_ILACE_TOP_FIRST
+#define LAV_INTER_BOTTOM_FIRST  Y4M_ILACE_BOTTOM_FIRST
+
+
+/* chroma_format */
+#define CHROMAUNKNOWN 0
+#define CHROMA420 1
+#define CHROMA422 2
+#define CHROMA444 3
+
+/* raw data format of a single frame */
+#define DATAFORMAT_MJPG     0
+#define DATAFORMAT_DV2      1
+#define DATAFORMAT_YUV420   2
+#define DATAFORMAT_YUV422   3
+
+typedef struct
+{
+   avi_t       *avi_fd;
+   int         jpeg_fd;
+   char        *jpeg_filename;
+#ifdef HAVE_LIBQUICKTIME
+   quicktime_t *qt_fd;
+#endif
+#ifdef HAVE_LIBMOVTAR
+   movtar_t    *movtar_fd;
+#endif
+   int         format;
+   int         interlacing;
+   int         sar_w;  /* "sample aspect ratio" width  */
+   int         sar_h;  /* "sample aspect ratio" height */
+   int         has_audio;
+   int         bps;
+   int         is_MJPG;
+   int         MJPG_chroma;
+} lav_file_t;
+
+int  lav_query_APP_marker(char format);
+int  lav_query_APP_length(char format);
+int  lav_query_polarity(char format);
+lav_file_t *lav_open_output_file(char *filename, char format,
+                    int width, int height, int interlaced, double fps,
+                    int asize, int achans, long arate);
+int  lav_close(lav_file_t *lav_file);
+int  lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count);
+int  lav_write_audio(lav_file_t *lav_file, uint8_t *buff, long samps);
+long lav_video_frames(lav_file_t *lav_file);
+int  lav_video_width(lav_file_t *lav_file);
+int  lav_video_height(lav_file_t *lav_file);
+double lav_frame_rate(lav_file_t *lav_file);
+int  lav_video_interlacing(lav_file_t *lav_file);
+void lav_video_sampleaspect(lav_file_t *lav_file, int *sar_w, int *sar_h);
+int  lav_video_is_MJPG(lav_file_t *lav_file);
+int  lav_video_MJPG_chroma(lav_file_t *lav_file);
+const char *lav_video_compressor(lav_file_t *lav_file);
+int  lav_audio_channels(lav_file_t *lav_file);
+int  lav_audio_bits(lav_file_t *lav_file);
+long lav_audio_rate(lav_file_t *lav_file);
+long lav_audio_samples(lav_file_t *lav_file);
+long lav_frame_size(lav_file_t *lav_file, long frame);
+int  lav_seek_start(lav_file_t *lav_file);
+int  lav_set_video_position(lav_file_t *lav_file, long frame);
+int  lav_read_frame(lav_file_t *lav_file, uint8_t *vidbuf);
+int  lav_set_audio_position(lav_file_t *lav_file, long sample);
+long lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps);
+int  lav_filetype(lav_file_t *lav_file);
+lav_file_t *lav_open_input_file(char *filename);
+int  lav_get_field_size(uint8_t * jpegdata, long jpeglen);
+const char *lav_strerror(void);
+int  lav_fileno( lav_file_t *lav_file );
+#endif
diff -Naur main/libmpdemux/mjpeg_logging.c main-mjpeg/libmpdemux/mjpeg_logging.c
--- main/libmpdemux/mjpeg_logging.c	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/mjpeg_logging.c	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,229 @@
+/*
+    $Id: mjpeg_logging.c,v 1.11 2002/04/16 16:10:14 mdoggydog Exp $
+
+    Copyright (C) 2000 Herbert Valerio Riedel <hvr at gnu.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+extern int fred;
+#include "mjpeg_logging.h"
+
+static const char _rcsid[] = "$Id: ";
+
+#define MAX_DEFAULT_ID_SIZE 16
+#define DEFAULT_DEFAULT_ID "???"
+
+#ifdef HAVE___PROGNAME
+extern const char *__progname;
+#endif
+
+static log_level_t mjpeg_log_verbosity = 0;
+static char default_handler_id[MAX_DEFAULT_ID_SIZE];
+static char default_handler_id_is_set = 0;
+
+static int default_mjpeg_log_filter( log_level_t level )
+{
+  int verb_from_env;
+  if( mjpeg_log_verbosity == 0 )
+    {
+      char *mjpeg_verb_env = getenv("MJPEG_VERBOSITY");
+      if( mjpeg_verb_env != NULL )
+        {
+          verb_from_env = LOG_WARN-atoi(mjpeg_verb_env);
+          if( verb_from_env >= LOG_DEBUG && verb_from_env <= LOG_ERROR )
+            mjpeg_log_verbosity = verb_from_env;
+        }
+    }
+  return (level < LOG_WARN && level < mjpeg_log_verbosity);
+}
+
+static mjpeg_log_filter_t _filter = default_mjpeg_log_filter;
+
+static void
+default_mjpeg_log_handler(log_level_t level, const char message[])
+{
+  const char *ids;
+
+  if( (*_filter)( level ) )
+    return;
+  if (default_handler_id_is_set) {
+    ids = default_handler_id;
+  } else {
+#ifdef HAVE___PROGNAME
+    ids = __progname;
+#else
+    ids = DEFAULT_DEFAULT_ID;
+#endif
+  }
+  switch(level) {
+  case LOG_ERROR:
+    fprintf(stderr, "**ERROR: [%s] %s\n", ids, message);
+    break;
+  case LOG_DEBUG:
+    fprintf(stderr, "--DEBUG: [%s] %s\n", ids, message);
+    break;
+  case LOG_WARN:
+    fprintf(stderr, "++ WARN: [%s] %s\n", ids, message);
+    break;
+  case LOG_INFO:
+    fprintf(stderr, "   INFO: [%s] %s\n", ids, message);
+    break;
+  default:
+    assert(0);
+  }
+}
+
+static mjpeg_log_handler_t _handler = default_mjpeg_log_handler;
+
+
+mjpeg_log_handler_t
+mjpeg_log_set_handler(mjpeg_log_handler_t new_handler)
+{
+  mjpeg_log_handler_t old_handler = _handler;
+
+  _handler = new_handler;
+
+  return old_handler;
+}
+
+/***************
+ *
+ * Set default log handlers degree of verboseity.
+ * 0 = quiet, 1 = info, 2 = debug
+ *
+ *************/
+
+int
+mjpeg_default_handler_verbosity(int verbosity)
+{
+  int prev_verb = mjpeg_log_verbosity;
+  mjpeg_log_verbosity = LOG_WARN - verbosity;
+  return prev_verb;
+}
+
+/*
+ * Set identifier string used by default handler
+ *
+ */
+int
+mjpeg_default_handler_identifier(const char *new_id)
+{
+  const char *s;
+  if (new_id == NULL) {
+    default_handler_id_is_set = 0;
+    return 0;
+  }
+  /* find basename of new_id (remove any directory prefix) */
+  if ((s = strrchr(new_id, '/')) == NULL)
+    s = new_id;
+  else
+    s = s + 1;
+  strncpy(default_handler_id, s, MAX_DEFAULT_ID_SIZE);
+  default_handler_id[MAX_DEFAULT_ID_SIZE-1] = '\0';
+  default_handler_id_is_set = 1;
+  return 0;
+}
+
+
+static void
+mjpeg_logv(log_level_t level, const char format[], va_list args)
+{
+  char buf[1024] = { 0, };
+
+  /* TODO: Original had a re-entrancy error trap to assist bug
+     finding.  To make this work with multi-threaded applications a
+     lock is needed hence delete.
+  */
+
+  
+  vsnprintf(buf, sizeof(buf)-1, format, args);
+
+  _handler(level, buf);
+}
+
+void
+mjpeg_log(log_level_t level, const char format[], ...)
+{
+  va_list args;
+  va_start (args, format);
+  mjpeg_logv(level, format, args);
+  va_end (args);
+}
+
+void
+mjpeg_debug(const char format[], ...)
+{
+  va_list args;
+  va_start (args, format);
+  mjpeg_logv(LOG_DEBUG, format, args);
+  va_end (args);
+}
+
+void
+mjpeg_info(const char format[], ...)
+{
+  va_list args;
+  va_start (args, format);
+  mjpeg_logv(LOG_INFO, format, args);
+  va_end (args);
+}
+
+void
+mjpeg_warn(const char format[], ...)
+{
+  va_list args;
+  va_start (args, format);
+  mjpeg_logv(LOG_WARN, format, args);
+  va_end (args);
+}
+
+void
+mjpeg_error(const char format[], ...)
+{
+  va_list args;
+  va_start (args, format);
+  mjpeg_logv(LOG_ERROR, format, args);
+  va_end (args);
+}
+
+void
+mjpeg_error_exit1(const char format[], ...)
+{
+  va_list args;
+  va_start( args, format );
+  mjpeg_logv( LOG_ERROR, format, args);
+  va_end(args);           
+  exit(EXIT_FAILURE);
+}
+
+
+/* 
+ * Local variables:
+ *  c-file-style: "gnu"
+ *  tab-width: 8
+ *  indent-tabs-mode: nil
+ * End:
+ */
diff -Naur main/libmpdemux/mjpeg_logging.h main-mjpeg/libmpdemux/mjpeg_logging.h
--- main/libmpdemux/mjpeg_logging.h	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/mjpeg_logging.h	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,79 @@
+/*
+    $Id: mjpeg_logging.h,v 1.6 2002/02/27 01:17:57 mdoggydog Exp $
+
+    Copyright (C) 2000 Herbert Valerio Riedel <hvr at gnu.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __MJPEG_LOGGING_H__
+#define __MJPEG_LOGGING_H__
+
+#include "mjpeg_types.h"
+
+typedef enum {
+  LOG_DEBUG = 1,
+  LOG_INFO,
+  LOG_WARN,
+  LOG_ERROR
+} log_level_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void
+mjpeg_log(log_level_t level, const char format[], ...) GNUC_PRINTF(2, 3);
+
+typedef int(*mjpeg_log_filter_t)(log_level_t level);
+    
+typedef void(*mjpeg_log_handler_t)(log_level_t level, const char message[]);
+
+mjpeg_log_handler_t
+mjpeg_log_set_handler(mjpeg_log_handler_t new_handler);
+
+int
+mjpeg_default_handler_identifier(const char *new_id);
+
+int
+mjpeg_default_handler_verbosity(int verbosity);
+
+void
+mjpeg_debug(const char format[], ...) GNUC_PRINTF(1,2);
+
+void
+mjpeg_info(const char format[], ...) GNUC_PRINTF(1,2);
+
+void
+mjpeg_warn(const char format[], ...) GNUC_PRINTF(1,2);
+
+void
+mjpeg_error(const char format[], ...) GNUC_PRINTF(1,2);
+
+void
+mjpeg_error_exit1(const char format[], ...) GNUC_PRINTF(1,2);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MJPEG_LOGGING_H__ */
+
+
+/* 
+ * Local variables:
+ *  c-file-style: "gnu"
+ *  tab-width: 8
+ *  indent-tabs-mode: nil
+ * End:
+ */
diff -Naur main/libmpdemux/mjpeg_types.h main-mjpeg/libmpdemux/mjpeg_types.h
--- main/libmpdemux/mjpeg_types.h	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/mjpeg_types.h	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,109 @@
+/*
+    $Id: mjpeg_types.h,v 1.6 2002/04/27 22:03:57 rbultje Exp $
+
+    Copyright (C) 2000 Herbert Valerio Riedel <hvr at gnu.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __MJPEG_TYPES_H__
+#define __MJPEG_TYPES_H__
+#include "config.h"
+
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#elif defined(__CYGWIN__)
+# include <sys/types.h>
+typedef u_int8_t uint8_t;
+typedef u_int16_t uint16_t;
+typedef u_int32_t uint32_t;
+typedef u_int64_t uint64_t;
+# define INT8_C(c)     c
+# define INT16_C(c)    c
+# define INT32_C(c)    c
+# define INT64_C(c)    c ## LL
+# define UINT8_C(c)    c ## U
+# define UINT16_C(c)   c ## U
+# define UINT32_C(c)   c ## U
+# define UINT64_C(c)   c ## ULL
+#else
+/* warning ISO/IEC 9899:1999 <stdint.h> was missing and even <inttypes.h> */
+/* fixme */
+#endif /* HAVE_STDINT_H */
+
+#if defined(__FreeBSD__)
+#include <sys/types.h> /* FreeBSD - ssize_t */
+#endif
+
+#if defined(HAVE_STDBOOL_H) && !defined(__cplusplus)
+#include <stdbool.h>
+#else
+/* ISO/IEC 9899:1999 <stdbool.h> missing -- enabling workaround */
+
+# ifndef __cplusplus
+typedef enum
+  {
+    false = 0,
+    true = 1
+  } locBool;
+
+#  define false   false
+#  define true    true
+#  define bool locBool
+# endif
+#endif
+
+#ifndef PRId64
+#define PRId64 PRID64_STRING_FORMAT
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define GNUC_PRINTF( format_idx, arg_idx )    \
+  __attribute__((format (printf, format_idx, arg_idx)))
+#define GNUC_SCANF( format_idx, arg_idx )     \
+  __attribute__((format (scanf, format_idx, arg_idx)))
+#define GNUC_FORMAT( arg_idx )                \
+  __attribute__((format_arg (arg_idx)))
+#define GNUC_NORETURN                         \
+  __attribute__((noreturn))
+#define GNUC_CONST                            \
+  __attribute__((const))
+#define GNUC_UNUSED                           \
+  __attribute__((unused))
+#define GNUC_PACKED                           \
+  __attribute__((packed))
+#else   /* !__GNUC__ */
+#define GNUC_PRINTF( format_idx, arg_idx )
+#define GNUC_SCANF( format_idx, arg_idx )
+#define GNUC_FORMAT( arg_idx )
+#define GNUC_NORETURN
+#define GNUC_CONST
+#define GNUC_UNUSED
+#define GNUC_PACKED
+#endif  /* !__GNUC__ */
+
+
+#endif /* __MJPEG_TYPES_H__ */
+
+
+/* 
+ * Local variables:
+ *  c-file-style: "gnu"
+ *  tab-width: 8
+ *  indent-tabs-mode: nil
+ * End:
+ */
diff -Naur main/libmpdemux/tv.c main-mjpeg/libmpdemux/tv.c
--- main/libmpdemux/tv.c	Mon Mar  3 10:59:07 2003
+++ main-mjpeg/libmpdemux/tv.c	Tue Mar 11 23:04:06 2003
@@ -63,6 +63,10 @@
 int tv_param_forcechan = -1;
 int tv_param_force_audio = 0;
 int tv_param_buffer_size = -1;
+int tv_param_mjpeg = 0;
+int tv_param_decimation = 2;
+int tv_param_interlace = 1;
+int tv_param_quality = 90;
 #ifdef HAVE_ALSA9
 int tv_param_alsa = 0;
 #endif
@@ -177,6 +181,22 @@
     if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) {
 	mp_msg(MSGT_TV, MSGL_ERR, "Error: cannot set norm!\n");
 	return 0;
+    }
+
+
+    if ( tv_param_mjpeg )
+    {
+      /* set width to expected value */
+      if (tv_param_width == -1)
+        {
+          tv_param_width = 704/tv_param_decimation;
+        }
+      if (tv_param_height == -1)
+        {
+          tv_param_height = 576/tv_param_decimation; 
+        }
+      mp_msg(MSGT_TV, MSGL_INFO, 
+	       "MJP: width %d height %d\n", tv_param_width, tv_param_height);
     }
 
     /* limits on w&h are norm-dependent -- JM */
diff -Naur main/libmpdemux/tv.h main-mjpeg/libmpdemux/tv.h
--- main/libmpdemux/tv.h	Sat Dec 28 22:57:39 2002
+++ main-mjpeg/libmpdemux/tv.h	Tue Mar 11 23:04:10 2003
@@ -34,6 +34,10 @@
 extern int tv_param_forcechan;
 extern int tv_param_force_audio;
 extern int tv_param_buffer_size;
+extern int tv_param_mjpeg;
+extern int tv_param_decimation;
+extern int tv_param_quality;
+extern int tv_param_interlace;
 #ifdef HAVE_ALSA9
 extern int tv_param_alsa;
 #endif
diff -Naur main/libmpdemux/tvi_v4l.c main-mjpeg/libmpdemux/tvi_v4l.c
--- main/libmpdemux/tvi_v4l.c	Sun Feb  2 02:36:35 2003
+++ main-mjpeg/libmpdemux/tvi_v4l.c	Tue Mar 11 23:04:35 2003
@@ -37,6 +37,9 @@
 #include "../libao2/afmt.h"
 #include "../libvo/img_format.h"
 #include "../libvo/fastmemcpy.h"
+#include "videodev_mjpeg.h"
+#include "../libavcodec/avcodec.h"
+#include "jpegutils.h"
 
 #include "tv.h"
 
@@ -128,6 +131,7 @@
     long long                   audio_skew_total;
     long			audio_recv_blocks_total;
     long			audio_sent_blocks_total;
+    long                        mjpeg_bufsize;
     
 } priv_t;
 
@@ -440,6 +444,90 @@
     priv->height = priv->capability.minheight;
     mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels);
 
+    /* somewhere here could disable tv_param_mjpeg, if it is not a capability */
+
+    /* initialize if necessary */
+    if ( tv_param_mjpeg )
+      {
+        struct mjpeg_params bparm;
+        struct mjpeg_requestbuffers breq;          /* buffer requests */
+
+        if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
+        {
+           mp_msg(MSGT_TV, MSGL_ERR, 
+              "MJP: Error getting video parameters: %s\n", sys_errlist[errno]);
+           goto err;
+        }
+
+        mp_msg(MSGT_TV, MSGL_INFO, 
+	       "MJP: previous params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n",
+	           bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height,          
+		   bparm.decimation, bparm.field_per_buff);
+
+        mp_msg(MSGT_TV, MSGL_INFO, 
+	       "MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n",
+	           bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm);
+
+        bparm.input = tv_param_input; /* tv */
+        bparm.norm =  0; /* PAL */
+        bparm.quality = tv_param_quality;
+        bparm.decimation = tv_param_decimation;
+
+        mp_msg(MSGT_TV, MSGL_INFO, "MJP: setting params to decimation: %d, quality: %d\n", 
+	                                 bparm.decimation, bparm.quality);
+
+        if (ioctl(priv->video_fd, MJPIOC_S_PARAMS, &bparm) < 0)
+         {
+            mp_msg(MSGT_TV, MSGL_ERR,
+               "MJP: Error setting video parameters: %s\n", sys_errlist[errno]);
+            goto err;
+         }
+
+        if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
+        {
+           mp_msg(MSGT_TV, MSGL_ERR, 
+              "MJP: Error getting video parameters: %s\n", sys_errlist[errno]);
+           goto err;
+        }
+
+        mp_msg(MSGT_TV, MSGL_INFO, 
+	       "MJP: current params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n",
+	           bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height,          
+		   bparm.decimation, bparm.field_per_buff);
+
+        mp_msg(MSGT_TV, MSGL_INFO, 
+	       "MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n",
+	           bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm);
+
+
+        breq.count = 64;
+	priv -> nbuf = breq.count;
+        priv->mbuf.frames = priv -> nbuf;
+        priv->mjpeg_bufsize = 256*1024;
+        if (tv_param_buffer_size >= 0) {
+          priv->mjpeg_bufsize = tv_param_buffer_size*1024;
+	  }
+        breq.size  = priv -> mjpeg_bufsize;
+        if (ioctl(priv->video_fd, MJPIOC_REQBUFS,&(breq)) < 0)
+        {
+           mp_msg (MSGT_TV, MSGL_ERR,
+              "MJP: Error requesting video buffers: %s\n", sys_errlist[errno]);
+           goto err;
+        }
+        mp_msg(MSGT_TV, MSGL_INFO,
+           "MJP: Got %ld buffers of size %ld KB\n", 
+                    breq.count, breq.size/1024);
+
+        priv -> mmap = mmap(0, breq.count * breq.size, 
+           PROT_READ|PROT_WRITE, MAP_SHARED, priv->video_fd, 0);
+        if (priv -> mmap == MAP_FAILED)
+        {
+           mp_msg(MSGT_TV, MSGL_INFO,
+              "MJP: Error mapping video buffers: %s\n", sys_errlist[errno]);
+           goto err;
+        }
+      }
+
     priv->channels = (struct video_channel *)malloc(sizeof(struct video_channel)*priv->capability.channels);
     if (!priv->channels)
 	goto malloc_failed;
@@ -469,6 +557,8 @@
 	goto err;
     }
     
+    if ( !tv_param_mjpeg )
+    {
     /* map grab buffer */
     if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1)
     {
@@ -495,6 +585,7 @@
     if (!priv->buf)
 	goto malloc_failed;
     memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap));
+    }
     
     /* init v4l audio even when we don't capture */
     init_v4l_audio(priv);
@@ -550,6 +641,7 @@
 
 static int uninit(priv_t *priv)
 {
+    unsigned long num;
     priv->shutdown = 1;
 
     mp_msg(MSGT_TV, MSGL_V, "Waiting for threads to finish... ");
@@ -568,6 +660,14 @@
 	ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]);
     }
     
+    if ( tv_param_mjpeg )
+      {
+	num = -1;
+        if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0)
+          {
+            mp_msg(MSGT_TV, MSGL_ERR, "\nMJP: ioctl MJPIOC_QBUF_CAPT failed: %s\n", strerror(errno));
+          }
+      }
     close(priv->video_fd);
 
     audio_in_uninit(&priv->audio_in);
@@ -653,6 +753,8 @@
 	return(0);
     }
 
+    if ( !tv_param_mjpeg )
+    {
     priv->nbuf = priv->mbuf.frames;
     for (i=0; i < priv->nbuf; i++)
     {
@@ -662,6 +764,7 @@
 	priv->buf[i].height = priv->height;
 	mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]);
     } 
+    } 
 
 #if 0
     {
@@ -1204,6 +1307,20 @@
     int i;
     unsigned char *sptr;
 
+    if ( tv_param_mjpeg )
+    {
+	priv->width  = 704/tv_param_decimation;
+	priv->height = PAL_HEIGHT/tv_param_decimation; 
+        if ( decode_jpeg_raw(source, priv->mjpeg_bufsize, tv_param_interlace, 0, 
+	                     704/tv_param_decimation, PAL_HEIGHT/tv_param_decimation, dest, 
+			     dest+priv->width * priv->height*5/4, 
+			     dest+priv->width * priv->height) != 0 ) 
+        {
+           mp_msg(MSGT_TV, MSGL_INFO, "\nMJP: Error decoding \n");
+        }
+	else return;
+    }
+
     // YV12 uses VIDEO_PALETTE_YUV420P, but the planes are swapped
     if (priv->format == IMGFMT_YV12) {
 	memcpy(dest, source, priv->width * priv->height);
@@ -1243,15 +1360,30 @@
     int i;
     int first = 1;
     int framecount;
+    unsigned long num;
 
     /* start the capture process */
 
-    for (i=0; i < priv->nbuf; i++) {
-	if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[i]) == -1)
-	{
-	    mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno));
-	}
-    }
+    if ( tv_param_mjpeg )
+      {
+        mp_msg(MSGT_TV, MSGL_INFO, "MJP: gonna capture ! \n");
+        for (i=0; i < priv->nbuf; i++) {
+	num = i;
+        if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0)
+          {
+            mp_msg(MSGT_TV, MSGL_ERR, "\nMJP: ioctl MJPIOC_QBUF_CAPT b failed: %s\n", strerror(errno));
+          }
+	  }
+      }
+    else
+      {
+        for (i=0; i < priv->nbuf; i++) {
+        if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[i]) == -1)
+          {
+            mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno));
+          }
+        }
+      }
 
     prev_interval = 0;
     prev_skew = 0;
@@ -1271,8 +1403,17 @@
 		
 	    frame = i;
 
+	    if ( tv_param_mjpeg )
+	    {
+	    while (ioctl(priv->video_fd, MJPIOC_SYNC, &priv->buf[frame].frame) < 0 &&
+		   (errno == EAGAIN || errno == EINTR));
+
+	    }
+	    else
+	    {
 	    while (ioctl(priv->video_fd, VIDIOCSYNC, &priv->buf[frame].frame) < 0 &&
 		   (errno == EAGAIN || errno == EINTR));
+	    }
 	    mp_dbg(MSGT_TV, MSGL_DBG3, "\npicture sync failed\n");
 
 	    gettimeofday(&curtime, NULL);
@@ -1358,20 +1499,38 @@
 		    priv->video_timebuffer[priv->video_tail] = interval - skew;
 		}
 		
+                if ( tv_param_mjpeg )
+		copy_frame(priv, priv->video_ringbuffer[priv->video_tail], 
+		           priv->mmap+(priv->mjpeg_bufsize)*i);
+		else
 		copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->mmap+priv->mbuf.offsets[frame]);
 		priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current;
 		priv->video_cnt++;
 	    }
 
+            if ( tv_param_mjpeg )
+            {
+	      num = frame;
+              if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0)
+                {
+                  mp_msg(MSGT_TV, MSGL_ERR, "\nMJP: ioctl MJPIOC_QBUF_CAPT end failed: %s\n", 
+		                                    strerror(errno));
+		  continue;
+                }
+	    }
+	    else
+	    {
 	    if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[frame]) == -1)
 	    {
 		mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno));
 		continue;
 	    }
+	    }
 
 	}
 
     }
+    mp_msg(MSGT_TV, MSGL_INFO, "MJP: returning! \n");
     return NULL;
 }
 
diff -Naur main/libmpdemux/videodev_mjpeg.h main-mjpeg/libmpdemux/videodev_mjpeg.h
--- main/libmpdemux/videodev_mjpeg.h	Thu Jan  1 00:00:00 1970
+++ main-mjpeg/libmpdemux/videodev_mjpeg.h	Tue Mar 11 22:55:00 2003
@@ -0,0 +1,118 @@
+/* These are the MJPEG API extensions for the Video4Linux API,
+   first introduced by the Iomega Buz driver by Rainer Johanni 
+   <rainer at johanni.de>
+*/
+
+/* This is identical with the mgavideo internal params struct, 
+   please tell me if you change this struct here ! <gz at lysator.liu.se) */
+struct mjpeg_params
+{
+
+   /* The following parameters can only be queried */
+
+   int major_version;            /* Major version number of driver */
+   int minor_version;            /* Minor version number of driver */
+
+   /* Main control parameters */
+
+   int input;                    /* Input channel: 0 = Composite, 1 = S-VHS */
+   int norm;                     /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+   int decimation;               /* decimation of captured video,
+                                    enlargement of video played back.
+                                    Valid values are 1, 2, 4 or 0.
+                                    0 is a special value where the user
+                                    has full control over video scaling */
+
+   /* The following parameters only have to be set if decimation==0,
+      for other values of decimation they provide the data how the image is captured */
+
+   int HorDcm;                    /* Horizontal decimation: 1, 2 or 4 */
+   int VerDcm;                    /* Vertical decimation: 1 or 2 */
+   int TmpDcm;                    /* Temporal decimation: 1 or 2,
+                                     if TmpDcm==2 in capture every second frame is dropped,
+                                     in playback every frame is played twice */
+   int field_per_buff;            /* Number of fields per buffer: 1 or 2 */
+   int img_x;                     /* start of image in x direction */
+   int img_y;                     /* start of image in y direction */
+   int img_width;                 /* image width BEFORE decimation,
+                                     must be a multiple of HorDcm*16 */
+   int img_height;                /* image height BEFORE decimation,
+                                     must be a multiple of VerDcm*8 */
+
+   /* --- End of parameters for decimation==0 only --- */
+
+   /* JPEG control parameters */
+
+   int  quality;                  /* Measure for quality of compressed images.
+                                     Scales linearly with the size of the compressed images.
+                                     Must be beetween 0 and 100, 100 is a compression
+                                     ratio of 1:4 */
+
+   int  odd_even;                 /* Which field should come first ???
+                                     This is more aptly named "top_first",
+                                     i.e. (odd_even==1) --> top-field-first */
+
+   int  APPn;                     /* Number of APP segment to be written, must be 0..15 */
+   int  APP_len;                  /* Length of data in JPEG APPn segment */
+   char APP_data[60];             /* Data in the JPEG APPn segment. */
+
+   int  COM_len;                  /* Length of data in JPEG COM segment */
+   char COM_data[60];             /* Data in JPEG COM segment */
+
+   unsigned long jpeg_markers;    /* Which markers should go into the JPEG output.
+                                     Unless you exactly know what you do, leave them untouched.
+                                     Inluding less markers will make the resulting code
+                                     smaller, but there will be fewer aplications
+                                     which can read it.
+                                     The presence of the APP and COM marker is
+                                     influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define JPEG_MARKER_APP (1<<7)    /* App segment, driver will allways use APP0 */
+
+   int  VFIFO_FB;                 /* Flag for enabling Video Fifo Feedback.
+                                     If this flag is turned on and JPEG decompressing
+                                     is going to the screen, the decompress process
+                                     is stopped every time the Video Fifo is full.
+                                     This enables a smooth decompress to the screen
+                                     but the video output signal will get scrambled */
+
+   /* Misc */
+
+	char reserved[312];  /* Makes 512 bytes for this structure */
+};
+
+struct mjpeg_requestbuffers
+{
+   unsigned long count;      /* Number of buffers for MJPEG grabbing */
+   unsigned long size;       /* Size PER BUFFER in bytes */
+};
+
+struct mjpeg_sync
+{
+   unsigned long frame;      /* Frame (0 - n) for double buffer */
+   unsigned long length;     /* number of code bytes in buffer (capture only) */
+   unsigned long seq;        /* frame sequence number */
+   struct timeval timestamp; /* timestamp */
+};
+
+struct mjpeg_status
+{
+   int input;                /* Input channel, has to be set prior to BUZIOC_G_STATUS */
+   int signal;               /* Returned: 1 if valid video signal detected */
+   int norm;                 /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+   int color;                /* Returned: 1 if color signal detected */
+};
+
+/*
+Private IOCTL to set up for displaying MJPEG
+*/
+#define MJPIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct mjpeg_params)
+#define MJPIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct mjpeg_params)
+#define MJPIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct mjpeg_requestbuffers)
+#define MJPIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define MJPIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define MJPIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct mjpeg_sync)
+#define MJPIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct mjpeg_status)


More information about the MPlayer-dev-eng mailing list