[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