[MPlayer-dev-eng] [PATCH] support for hardware mjpeg encoding in tvi_v4l.c (version 3)
Ivan Szanto
szivan at duticai.TWI.TUDelft.NL
Wed Mar 19 01:31:40 CET 2003
Hi,
> > Shall I send a new version of the patch, or "The Brave" will
> > be able to apply that "Hunk #12" by hand? Of course, I see
> > little sense in sending the new version, unless someone is
> > willing to apply it ...
> just tried (with patch -F3)
>
> tv.c: In function `open_tv':
> tv.c:186: `tv_param_mjpeg' undeclared (first use in this function)
> tv.c:186: (Each undeclared identifier is reported only once
> tv.c:186: for each function it appears in.)
> tv.c:191: `tv_param_decimation' undeclared (first use in this function)
> make: *** [tv.o] Error 1
>
> [...]
>
> Michael
Please try the updated version, which I'm sending now.
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 18 22:21:28 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 Sun Mar 16 20:13:06 2003
+++ main-mjpeg/cfg-common.h Tue Mar 18 22:21:28 2003
@@ -286,6 +286,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
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 18 22:21:28 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 Tue Mar 18 22:21:28 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 Mar 16 16:38:16 2003
+++ main-mjpeg/libmpdemux/tvi_v4l.c Tue Mar 18 22:22:43 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"
@@ -132,6 +136,7 @@
long long audio_skew_total;
long audio_recv_blocks_total;
long audio_sent_blocks_total;
+ long mjpeg_bufsize;
} priv_t;
@@ -443,8 +448,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;
@@ -474,6 +568,8 @@
goto err;
}
+ if ( !tv_param_mjpeg )
+ {
/* map grab buffer */
if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1)
{
@@ -500,6 +596,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);
@@ -555,6 +652,7 @@
static int uninit(priv_t *priv)
{
+ unsigned long num;
priv->shutdown = 1;
mp_msg(MSGT_TV, MSGL_V, "Waiting for threads to finish... ");
@@ -573,6 +671,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);
@@ -660,6 +766,8 @@
return(0);
}
+ if ( !tv_param_mjpeg )
+ {
priv->nbuf = priv->mbuf.frames;
for (i=0; i < priv->nbuf; i++)
{
@@ -669,6 +777,7 @@
priv->buf[i].height = priv->height;
mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]);
}
+ }
#if 0
{
@@ -853,8 +962,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:
@@ -1263,14 +1383,30 @@
int i;
int framecount;
int tolerance;
+ unsigned long num;
/* start the capture process */
+ 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));
}
+ }
}
gettimeofday(&curtime, NULL);
@@ -1301,8 +1437,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);
@@ -1405,20 +1550,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;
}
More information about the MPlayer-dev-eng
mailing list