[MPlayer-dev-eng] small patch to set FPS on v4l2 capture devices

Jaijeet Roychowdhury jr at berkeley.edu
Sat Aug 20 09:02:26 EEST 2016


I have made a small patch (attached) that sets a v4l2 capture device's fps if -tv fps=xxx is specified by mplayer/mencoder.

Without this patch, the capture device's fps is not set, resulting in the device (a Magewell USB Capture HDMI device, the only such device I have) sending frames at its maximum fps (60, for the Magewell). This leads to frame drops and video buffer overflows (the latter if mplayer's -fps and -ofps are set to some other value).

With the patch, it seems to work properly with, eg, the following command (which produces video buffer overflow messages without the patch):

mencoder -fps 29.97 -ofps 29.97   -tv device=/dev/video0:width=640:height=480:norm=ntsc:alsa:adevice=front.CARD=XI100DUSBHDMI,DEV=0:immediatemode=0:forceaudio:buffersize=64:audiorate=48000:amode=1:fps=29.97 -ovc x264 -x264encopts preset=veryfast:crf=22:threads=2  -oac mp3lame -lameopts fast:preset=medium -o try.avi tv://

Please consider incorporating it into the main code base. I have not tested it exhaustively, but would be glad to test further with the Magewell device if needed.

Thanks,

Jaijeet
-------------- next part --------------
diff -Naur MPlayer-1.3.0/stream/tv.c MPlayer-1.3.0-JR-setfps-patched/stream/tv.c
--- MPlayer-1.3.0/stream/tv.c	2016-02-13 09:03:23.000000000 -0800
+++ MPlayer-1.3.0-JR-setfps-patched/stream/tv.c	2016-08-19 21:27:41.489480360 -0700
@@ -420,6 +420,7 @@
 static int open_tv(tvi_handle_t *tvh)
 {
     int i;
+    double fps;
     const tvi_functions_t *funcs = tvh->functions;
     static const int tv_fmt_list[] = {
       IMGFMT_YV12,
@@ -512,27 +513,28 @@
         funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH_HEIGHT, dim);
     }
     /* set width */
-    if (tvh->tv_param->width != -1)
-    {
-	if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_WIDTH, &tvh->tv_param->width) == TVI_CONTROL_TRUE)
-	    funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH, &tvh->tv_param->width);
-	else
-	{
-	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_UnableToSetWidth, tvh->tv_param->width);
-	    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &tvh->tv_param->width);
-	}
+    if (tvh->tv_param->width != -1) {
+        if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_WIDTH, &tvh->tv_param->width) == TVI_CONTROL_TRUE)
+            funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH, &tvh->tv_param->width);
+        else {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_UnableToSetWidth, tvh->tv_param->width);
+            funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &tvh->tv_param->width);
+        }
     }
 
     /* set height */
-    if (tvh->tv_param->height != -1)
-    {
-	if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_HEIGHT, &tvh->tv_param->height) == TVI_CONTROL_TRUE)
-	    funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HEIGHT, &tvh->tv_param->height);
-	else
-	{
-	    mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_UnableToSetHeight, tvh->tv_param->height);
-	    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &tvh->tv_param->height);
-	}
+    if (tvh->tv_param->height != -1) {
+        if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_HEIGHT, &tvh->tv_param->height) == TVI_CONTROL_TRUE)
+            funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HEIGHT, &tvh->tv_param->height);
+        else {
+            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_UnableToSetHeight, tvh->tv_param->height);
+            funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &tvh->tv_param->height);
+        }
+    }
+
+    /* set parm (fps) */
+    if (tvh->tv_param->fps != -1) { 
+        funcs->control(tvh->priv, TVI_CONTROL_VID_SET_FPS, 0); // arg unused; getfps() within gets the framerate
     }
 
     if (funcs->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE)
diff -Naur MPlayer-1.3.0/stream/tv.h MPlayer-1.3.0-JR-setfps-patched/stream/tv.h
--- MPlayer-1.3.0/stream/tv.h	2010-09-13 11:09:29.000000000 -0700
+++ MPlayer-1.3.0-JR-setfps-patched/stream/tv.h	2016-08-19 21:48:16.457997297 -0700
@@ -200,6 +200,7 @@
 #define TVI_CONTROL_VID_SET_GAIN	0x11f
 #define TVI_CONTROL_VID_GET_GAIN	0x120
 #define TVI_CONTROL_VID_SET_WIDTH_HEIGHT	0x121
+#define TVI_CONTROL_VID_SET_FPS     0x122
 
 /* TUNER controls */
 #define TVI_CONTROL_TUN_GET_FREQ	0x201
diff -Naur MPlayer-1.3.0/stream/tvi_v4l2.c MPlayer-1.3.0-JR-setfps-patched/stream/tvi_v4l2.c
--- MPlayer-1.3.0/stream/tvi_v4l2.c	2014-06-10 09:39:04.000000000 -0700
+++ MPlayer-1.3.0-JR-setfps-patched/stream/tvi_v4l2.c	2016-08-19 21:50:06.480901539 -0700
@@ -753,6 +753,8 @@
 {
     struct v4l2_control control;
     struct v4l2_frequency frequency;
+    struct v4l2_streamparm parm; /* get/set parm */
+    float fps;
 
     switch(cmd) {
     case TVI_CONTROL_IS_VIDEO:
@@ -768,8 +770,25 @@
         return TVI_CONTROL_TRUE;
     case TVI_CONTROL_VID_GET_FPS:
         *(float *)arg = getfps(priv);
-        mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name,
-               *(float *)arg);
+        mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name, *(float *)arg);
+        return TVI_CONTROL_TRUE;
+    case TVI_CONTROL_VID_SET_FPS:
+        fps = getfps(priv);
+		memset(&parm, 0, sizeof(parm));
+        parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        parm.parm.capture.timeperframe.numerator = 1000;
+        parm.parm.capture.timeperframe.denominator = fps * parm.parm.capture.timeperframe.numerator;
+
+        if (ioctl(priv->video_fd, VIDIOC_S_PARM, &parm) < 0) {
+        	mp_msg(MSGT_TV, MSGL_ERR,"control: ioctl set fps failed: %s\n", info.short_name, strerror(errno));
+        	return  TVI_CONTROL_FALSE;
+		} else { // should have returned == 0
+			struct v4l2_fract *tf = &parm.parm.capture.timeperframe;
+            if (!tf->denominator || !tf->numerator)
+        		mp_msg(MSGT_TV,MSGL_WARN,"control: ioctl set fps: invalid frame rate\n");
+            else
+        		mp_msg(MSGT_TV,MSGL_V,"control: ioctl set fps: frame rate set to %0.3fps\n", 1.0*tf->denominator / tf->numerator);
+        }
         return TVI_CONTROL_TRUE;
     case TVI_CONTROL_VID_GET_BITS:
         if (getfmt(priv) < 0) return TVI_CONTROL_FALSE;


More information about the MPlayer-dev-eng mailing list