[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