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:
parent
391a1c6e72
commit
9a1bfa7ec1
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user