[MPlayer-dev-eng] enhancement for yuv4mpeg output driver, take 2

Trent Piepho xyzzy at speakeasy.org
Thu Jan 20 05:33:45 CET 2005


On Thu, 20 Jan 2005, Michael Niedermayer wrote:
> > I found av_reduce() in lavc, but it doesn't work for this.  Depending on
> > what I specify for the max, it turns 23.976 into 2996973/125000, 983/41,
> > 456427/19037, or 16831/702.  There doesn't seem to be any way to get the
> > correct value of 24000/1001.
> 
> try to set max to 30000

Did that, that's where the 16831/702 came from.  Even if it did work, you
would get incorrect results for the valid NTSC rate of 60000/1001.

I've created a new patch, which does the correct thing in every case I could
think of, and reduces the fractions when possible.
-------------- next part --------------
Index: libvo/vo_yuv4mpeg.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_yuv4mpeg.c,v
retrieving revision 1.20
diff -u -u -r1.20 vo_yuv4mpeg.c
--- libvo/vo_yuv4mpeg.c	31 Dec 2004 14:54:58 -0000	1.20
+++ libvo/vo_yuv4mpeg.c	20 Jan 2005 04:19:22 -0000
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h>
 
 #include "config.h"
 #include "subopt-helper.h"
@@ -42,6 +43,8 @@
 #include "postproc/rgb2rgb.h"
 #include "libmpcodecs/vf_scale.h"
 
+#include "libavcodec/avcodec.h"
+
 static vo_info_t info = 
 {
 	"yuv4mpeg output for mjpegtools",
@@ -66,6 +69,8 @@
 
 static char *yuv_filename = NULL;
 
+static int asp_x = 0, asp_y = 0; /* pixel aspect ratio */
+
 static int using_format = 0;
 static FILE *yuv_out;
 static int write_bytes;
@@ -78,10 +83,26 @@
 static int config_interlace = Y4M_ILACE_NONE;
 #define Y4M_IS_INTERLACED (config_interlace != Y4M_ILACE_NONE)
 
+/* Takes floating point number and tries to convert it to a fraction
+   of the form ret/den, where ret is the return value and den is
+   supplied.  If ret/den not within EPSILON of the flointing point
+   number, then 0 is returned instead. */
+static uint32_t try_denom(double frac, uint32_t den)
+{
+#define EPSILON	((double).0005)
+	double f = frac * den, f_int = rint(f);
+
+	if(fabs(f_int - f) < (EPSILON*den))
+		return f_int;
+	return 0;
+#undef EPSILON
+}
+
 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, 
        uint32_t d_height, uint32_t fullscreen, char *title, 
        uint32_t format)
 {
+	uint32_t n,d;
 	if (image_width == width && image_height == height &&
 	     image_fps == vo_fps && vo_config_count)
 	  return 0;
@@ -153,14 +174,28 @@
 	image_u = image_y + image_width * image_height;
 	image_v = image_u + image_width * image_height / 4;
 	
-	// This isn't right.  
-	// But it should work as long as the file isn't interlaced
-	// or otherwise unusual (the "Ip A0:0" part).
-
-	/* At least the interlacing is ok now */
-	fprintf(yuv_out, "YUV4MPEG2 W%d H%d F%ld:%ld I%c A0:0\n", 
-			image_width, image_height, (long)(image_fps * 1000000.0), 
-			(long)1000000, config_interlace);
+	/* Try to convert frame rate from floating point value to the
+	   correct fraction. */
+	if(!(n = try_denom(image_fps, d=1)))  /* try denominator of 1 */
+		if(!(n = try_denom(image_fps, d=1001))) /* ok, NTSC-style 1001 */
+			if(!(n = try_denom(image_fps, d=2))) /* maybe 2?? */
+			{
+				d = 1000000; n = image_fps * d; /* give up, use a million */
+			}
+
+	fprintf(yuv_out, "YUV4MPEG2 W%d H%d F%u:%u I%c ", image_width, image_height,
+	        n, d, config_interlace);
+
+	if(!asp_x && !asp_y) 
+	{
+		/* Not user-specified, try to guess sample aspect */
+		if(!av_reduce(&asp_x, &asp_y, d_width*height, d_height*width, 1000)) 
+		{
+			/* Didn't reduce without rounding, use un-reduce values */
+			asp_x = d_width*height; asp_y = d_height*width;
+		}
+	}
+	fprintf(yuv_out, "A%d:%d\n", asp_x, asp_y);
 
 	fflush(yuv_out);
 	return 0;
@@ -493,20 +528,31 @@
 {
 }
 
+static int ratio_p(strarg_t *norm) {
+	int foo;
+	if(sscanf(norm->str, "%d/%d",&foo,&foo)!=2) {
+		mp_msg(MSGT_VO, MSGL_ERR,
+		       "vo_yuv4mpeg: aspect argument must be a ratio of the form xxx/yyy\n");
+		return 0;
+	} else return 1;
+}
+
 static uint32_t preinit(const char *arg)
 {
   int il, il_bf;
-  strarg_t file;
+  strarg_t file, aspect;
   opt_t subopts[] = {
     {"interlaced",    OPT_ARG_BOOL, &il,    NULL},
     {"interlaced_bf", OPT_ARG_BOOL, &il_bf, NULL},
     {"file",          OPT_ARG_STR,  &file,  NULL},
+    {"aspect",        OPT_ARG_STR,  &aspect, (opt_test_f)ratio_p},
     {NULL}
   };
 
   il = 0;
   il_bf = 0;
   file.len = 0;
+  aspect.len = 0;
   if (subopt_parse(arg, subopts) != 0) {
     mp_msg(MSGT_VO, MSGL_FATAL, MSGTR_VO_YUV4MPEG_UnknownSubDev, arg); 
     return -1;
@@ -524,6 +570,12 @@
     yuv_filename[file.len] = 0;
   }
 
+  if (aspect.len > 0) {
+    if(sscanf(aspect.str, "%d/%d", &asp_x, &asp_y)!=2) {
+      /* some kind of error understanding the argument */
+    }
+  }
+
     /* Inform user which output mode is used */
     switch (config_interlace)
     {


More information about the MPlayer-dev-eng mailing list