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

Ivan Szanto szivan at duticai.TWI.TUDelft.NL
Thu Mar 13 03:09:16 CET 2003


Hi Rich,


thank you for the correction:

> On Wed, Mar 12, 2003 at 01:32:35AM +0100, Ivan Szanto wrote:
> > +.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
>
> These numbers are only valid for PAL. NTSC should be 704x480, 352x240,
> and 176x120.

You are right (at least I hope you are ;-), cause I now used that data)

But I'm a little bit in doubt. In patches.txt it does not actually
say that I should implement everything in one go. In the previous
versions of this patch (v1 and v2), PAL was implemented, NTSC was not,
since I cannot test NTSC. Is this now a reason not to commit my patch?

I mean obvious mistakes should of course not be committed, but was this
one? Maybe this depends on the maintainers' personal judgement?

This is just a kind request for some clarification... :-)
BTW, after all that discussion about the maintainer of the main tree,
it would also be nice to know, who will review/commit this patch.
I beleive the patch would be of use for everyone who has a tv-card that
supports hardware mjpeg encoding. Or aren't there such people on this
list? ;-)

Anyway, I made the change to the manpage and to the code, so v3 (see
below) should now support NTSC. (=please disregard v1 and v2 of this
patch)

greetings to everyone,

Ivan
-------------- next part --------------
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	Thu Mar 13 02:18:25 2003
@@ -63,6 +63,9 @@
 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_quality = 90;
 #ifdef HAVE_ALSA9
 int tv_param_alsa = 0;
 #endif
@@ -177,6 +180,25 @@
     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)
+        {
+	  if ( tvh->norm != TV_NORM_NTSC )
+            tv_param_height = 576/tv_param_decimation; 
+	  else
+            tv_param_height = 480/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	Thu Mar 13 02:18:31 2003
@@ -34,6 +34,9 @@
 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;
 #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	Thu Mar 13 02:39:33 2003
@@ -9,6 +9,9 @@
   Multithreading, a/v sync and native ALSA support by
     Jindrich Makovicka <makovick at kmlinux.fjfi.cvut.cz>
 
+  Mjpeg hardware encoding support by 
+    Iv?n Sz?nt? <szivan at freemail.hu>
+
   CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE!
 */
 
@@ -37,6 +40,7 @@
 #include "../libao2/afmt.h"
 #include "../libvo/img_format.h"
 #include "../libvo/fastmemcpy.h"
+#include "../libvo/videodev_mjpeg.h"
 
 #include "tv.h"
 
@@ -128,6 +132,7 @@
     long long                   audio_skew_total;
     long			audio_recv_blocks_total;
     long			audio_sent_blocks_total;
+    long                        mjpeg_bufsize;
     
 } priv_t;
 
@@ -438,8 +443,97 @@
 	priv->capability.maxwidth, priv->capability.maxheight);
     priv->width = priv->capability.minwidth;
     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 */
+        if (!strcasecmp(tv_param_norm, "pal"))
+	  bparm.norm =  0; /* PAL */
+        else if (!strcasecmp(tv_param_norm, "ntsc"))
+	  bparm.norm =  1; /* NTSC */
+        else if (!strcasecmp(tv_param_norm, "secam"))
+	  bparm.norm =  2; /* SECAM */
+        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;
+        }
+      }
+
+    mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels);
     priv->channels = (struct video_channel *)malloc(sizeof(struct video_channel)*priv->capability.channels);
     if (!priv->channels)
 	goto malloc_failed;
@@ -469,6 +563,8 @@
 	goto err;
     }
     
+    if ( !tv_param_mjpeg )
+    {
     /* map grab buffer */
     if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1)
     {
@@ -495,6 +591,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 +647,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 +666,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, "\n  MJP: ioctl MJPIOC_QBUF_CAPT failed: %s\n", strerror(errno));
+          }
+      }
     close(priv->video_fd);
 
     audio_in_uninit(&priv->audio_in);
@@ -653,6 +759,8 @@
 	return(0);
     }
 
+    if ( !tv_param_mjpeg )
+    {
     priv->nbuf = priv->mbuf.frames;
     for (i=0; i < priv->nbuf; i++)
     {
@@ -662,6 +770,7 @@
 	priv->buf[i].height = priv->height;
 	mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]);
     } 
+    } 
 
 #if 0
     {
@@ -834,8 +943,19 @@
 	    int output_fmt = -1;
 
 	    output_fmt = priv->format;
+            if ( tv_param_mjpeg )
+	    {
+              mp_msg(MSGT_TV, MSGL_INFO, "  MJP: setting sh_video->format to mjpg\n");
+	      output_fmt = 0x47504a4d;
+	      output_fmt = 0x67706a6d;
+	      (int)*(void **)arg = output_fmt;
+	      mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", "mjpg");
+	    }
+	    else
+	    {
 	    (int)*(void **)arg = output_fmt;
 	    mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", vo_format_name(output_fmt));
+	    }
 	    return(TVI_CONTROL_TRUE);
 	}
 	case TVI_CONTROL_VID_SET_FORMAT:
@@ -1243,15 +1363,31 @@
     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, 
+	           "\n  MJP: 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 +1407,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 +1503,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, "\n  MJP: 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/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        Thu Mar 13 02:01:58 2003
@@ -787,6 +787,31 @@
 (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=<1,2,4>
+choose the size of the picture that will be compressed by hardware
+mjpeg compression:
+.RSss
+1: full size 
+    704x576    PAL 
+    704x480    NTSC
+.br
+2: medium size 
+    352x288    PAL
+    352x240    NTSC
+.br
+4: small size 
+    176x144    PAL 
+    176x120    NTSC
+.REss
+.IPs quality=<0-100>
+choose the quality of the jpeg compression 
+.br
+(quality < 60 recommended for full size)
 .RE
 .
 .TP
diff -Naur main/cfg-common.h main-mjpeg/cfg-common.h
--- main/cfg-common.h	Thu Mar 13 02:27:00 2003
+++ main-mjpeg/cfg-common.h	Thu Mar 13 02:27:07 2003
@@ -279,6 +279,9 @@
 	{"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, 0, 100, NULL},
 #ifdef HAVE_ALSA9
 	{"alsa", &tv_param_alsa, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 #endif


More information about the MPlayer-dev-eng mailing list