1
mirror of https://github.com/mpv-player/mpv synced 2025-01-01 04:36:24 +01:00

hardware mjpeg encoding using v4l by Iván Szántó <szivan@freemail.hu>

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9621 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
henry 2003-03-19 16:26:58 +00:00
parent 391a1c6e72
commit 9a1bfa7ec1
5 changed files with 219 additions and 1 deletions

View File

@ -787,6 +787,31 @@ A value of 0 means capture and buffer audio and video together
(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

View File

@ -286,6 +286,9 @@ struct config tvopts_conf[]={
{"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

View File

@ -63,6 +63,9 @@ int tv_param_balance = -1;
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
@ -179,6 +182,27 @@ static int open_tv(tvi_handle_t *tvh)
return 0;
}
#ifdef HAVE_TV_V4L
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);
}
#endif
/* limits on w&h are norm-dependent -- JM */
/* set width */
if (tv_param_width != -1)

View File

@ -34,6 +34,9 @@ extern int tv_param_balance;
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

View File

@ -9,6 +9,9 @@
Multithreading, a/v sync and native ALSA support by
Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz>
Mjpeg hardware encoding support by
Iván Szántó <szivan@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 @@ typedef struct {
long long audio_skew_total;
long audio_recv_blocks_total;
long audio_sent_blocks_total;
long mjpeg_bufsize;
} priv_t;
@ -443,8 +448,97 @@ static int init(priv_t *priv)
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 @@ static int init(priv_t *priv)
goto err;
}
if ( !tv_param_mjpeg )
{
/* map grab buffer */
if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1)
{
@ -500,6 +596,7 @@ static int init(priv_t *priv)
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 @@ err:
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 @@ static int uninit(priv_t *priv)
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 @@ static int start(priv_t *priv)
return(0);
}
if ( !tv_param_mjpeg )
{
priv->nbuf = priv->mbuf.frames;
for (i=0; i < priv->nbuf; i++)
{
@ -669,6 +777,7 @@ static int start(priv_t *priv)
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 @@ static int control(priv_t *priv, int cmd, void *arg)
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 @@ static void *video_grabber(void *data)
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 @@ static void *video_grabber(void *data)
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 @@ static void *video_grabber(void *data)
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;
}