small patch to set FPS on v4l2 capture devices

Jaijeet Roychowdhury <[email protected]>
Newsgroups gmane.comp.video.mplayer.devel
Message-ID <20160820060226.GA28026@potol>
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

_______________________________________________
MPlayer-dev-eng mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
mplayer-JR-tv-v4l2-fps-patch--2016-08-19.txt (text/plain, 4.8 KB)
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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.