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

Trent Piepho xyzzy at speakeasy.org
Thu Jan 20 16:16:36 CET 2005


On Thu, 20 Jan 2005, D Richard Felker III wrote:
> On Thu, Jan 20, 2005 at 05:41:43AM -0800, Trent Piepho wrote:
> > My code is in the patch I attached to my email.  Do you mean how I'm using the
> > functions from lavc to try to convert mplayer's floating-point framerate to the
> > correct fractional value?  This is what I tried:
> > 
> > {
> >     AVRational a = av_d2q(image_fps, 60000);
> >     fprintf(stderr, "av_d2q to %d/%d\n", a.num, a.den);
> > }
> 
> Show us the whole program. You probably messed up something else.

I already posted the patch, but here it is again.  I dare you to make av_d2q
produce the correct results in every case.

-------------- next part --------------
Index: libvo/vo_yuv4mpeg.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_yuv4mpeg.c,v
retrieving revision 1.20
diff -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 15:06:38 -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,39 @@
 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
+}
+
+/* Find greatest common divisor of two numbers, using Euclid's method */
+static uint32_t gcd(uint32_t a, uint32_t b)
+{
+	return b ? gcd(b, a%b) : a;
+}
+
+/* Reduce a fraction to lowest terms */
+static void reduce(uint32_t *n, uint32_t *d)
+{
+	uint32_t g = gcd(*n, *d);
+	*n /= g; *d /= g;
+}
+
 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 +187,32 @@
 	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);
+	{
+		AVRational a = av_d2q(image_fps, 60000);
+		fprintf(stderr, "av_d2q to %d/%d\n", a.num, a.den);
+	}
+	/* 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 */
+				reduce(&n, &d);
+			}
+	fprintf(stderr, "my method to %d/%d\n", n, d);
+
+	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 */
+		n = d_width*height; d = d_height*width;
+		reduce(&n, &d);
+		asp_x = n; asp_y = d;
+	}
+	fprintf(yuv_out, "A%d:%d\n", asp_x, asp_y);
 
 	fflush(yuv_out);
 	return 0;
@@ -493,20 +545,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 +587,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