[MPlayer-dev-eng] [PATCH] using sh_video format for supporting hardware mjpegencoding in tvi_v4l.c

Ivan Szanto szivan at duticai.TWI.TUDelft.NL
Wed Mar 12 01:32:35 CET 2003


Hi,

> > 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
>
> nonsense!!!!!!!!
>
> >    better method. Please let me know about that better method.
>
> yes, set sh_video->fprmat to MJPG
> and let libmpcodecs to do the decoding

yes! that's what I meant! thanks Arpi! And (of course) this can
do things faster!

Please see the attached patch (and disregard the previous one).

Changes:

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

the rest is in the libmpdemux directory:

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


Hope this is ok now.

Greetings,

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/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
--- main/libmpdemux/tvi_v4l.c	Sun Feb  2 02:36:35 2003
+++ main-mjpeg/libmpdemux/tvi_v4l.c	Wed Mar 12 01:13:06 2003
@@ -37,6 +37,7 @@
 #include "../libao2/afmt.h"
 #include "../libvo/img_format.h"
 #include "../libvo/fastmemcpy.h"
+#include "../libvo/videodev_mjpeg.h"
 
 #include "tv.h"
 
@@ -128,6 +129,7 @@
     long long                   audio_skew_total;
     long			audio_recv_blocks_total;
     long			audio_sent_blocks_total;
+    long                        mjpeg_bufsize;
     
 } priv_t;
 
@@ -440,6 +442,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 +555,8 @@
 	goto err;
     }
     
+    if ( !tv_param_mjpeg )
+    {
     /* map grab buffer */
     if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1)
     {
@@ -495,6 +583,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 +639,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 +658,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 +751,8 @@
 	return(0);
     }
 
+    if ( !tv_param_mjpeg )
+    {
     priv->nbuf = priv->mbuf.frames;
     for (i=0; i < priv->nbuf; i++)
     {
@@ -662,6 +762,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 +935,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 +1355,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 +1398,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 +1494,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;
 }
 


More information about the MPlayer-dev-eng mailing list