[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