Mod16 Anamorphic

Archive of historical development discussions
Discussions / Development has moved to GitHub
Forum rules
*******************************
Please be aware we are now using GitHub for issue tracking and feature requests.
- This section of the forum is now closed to new topics.

*******************************
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Mod16 Anamorphic

Post by jbrjake »

Right now, when you encode with anamorphic, it simply crops away the black and uses what's left for the picture dimensions.

Invariably, those dimensions are not mod16, so x264 whines that the compression will suffer. Plus, you get a green line when you take screenshots in VLC.

Anyway, this behavior is intentional; clee wants to avoid rescaling the video...this speeds up encoding. But it kinda bugs me so I slapped in some code to correct the dimensions:

Code: Select all

Index: libhb/work.c
===================================================================
--- libhb/work.c        (revision 451)
+++ libhb/work.c        (working copy)
@@ -112,8 +112,14 @@
        /* Correct the geometry of the output movie when using PixelRatio */
        job->height=title->height-job->crop[0]-job->crop[1];
        job->width=title->width-job->crop[2]-job->crop[3];
-    }
 
+       /* And use mod16 values for better compression */
+       job->width   = MULTIPLE_16( job->width );
+               job->height  = MULTIPLE_16( job->height );
+               job->width   = MAX( 16, job->width );
+               job->height  = MAX( 16, job->height );    
+       }
+
        /* Keep width and height within these boundaries */
        if (job->maxHeight && (job->height > job->maxHeight) )
        {
But I don't know how to go about implementing it. I'd rather leave clee's default anamorphic behavior as it is. At the same time, I don't want to add yet another command line flag or graphical widget. So until I can figure out some way to do this, or until someone else suggests a course of action, I'll just leave it as an uncommitted patch.
saintdev
Enlightened
Posts: 146
Joined: Wed Dec 20, 2006 4:17 am

Post by saintdev »

Well here's an update to said patch, not committing for the same reasons.

Basically the same thing as jbrjake's, but this corrects the SAR so that we have the correct aspect ratio for the scaled mod16 dimensions.

Code: Select all

Index: libhb/work.c
===================================================================
--- libhb/work.c        (revision 569)
+++ libhb/work.c        (working copy)
@@ -112,8 +112,20 @@
     if ( job->pixel_ratio == 1 )
     {
        /* Correct the geometry of the output movie when using PixelRatio */
-       job->height=title->height-job->crop[0]-job->crop[1];
-       job->width=title->width-job->crop[2]-job->crop[3];
+       job->height = title->height - job->crop[0] - job->crop[1];
+       job->width = title->width - job->crop[2] - job->crop[3];
+
+        /* And use mod16 values for better compression */
+        job->width   = MULTIPLE_16( job->width );
+        job->height  = MULTIPLE_16( job->height );
+        job->width   = MAX( 16, job->width );
+        job->height  = MAX( 16, job->height );
+
+        /* Now correct the PAR for our mod16 picture */
+        hb_reduce( &job->pixel_aspect_width, &job->pixel_aspect_height,
+                   job->height * (title->width - job->crop[2] - job->crop[3]) * ((float)job->pixel_aspect_width / (float)job->pixel_aspect_height),
+                   job->width * (title->height - job->crop[0] - job->crop[1])
+                 );
     }
 
        /* Keep width and height within these boundaries */
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

Ok, here's a more flexible way of doing anamorphic. Opinions?

This patch adds a -P flag to the CLI. When it's used, it sets job->pixel_ratio to 2 (as opposed to the 1 that's already used for anamorphic.)

-P, unlike -p:

* corrects the dimensions so they divide cleanly by 16

* uses ITU PAR values if the width is <= 706 (ITU specs have NTSC 16x9 video at 704*480 instead of 720*480, and use a PAR of 40/33 instead of 32/27. Because HandBrake's cropping sucks and sometimes misses a couple of pixels on the sides, I figured I'd give it a two-pixel leeway)

* pays attention to the width the user enters instead of defaulting to the cropped width of the source frame (which is what it does if a width isn't given) -- anotherwords it lets people play around with pointless downscaled anamorphic rips on the iPod

* corrects the PAR for the output dimensions like saintdev's patch above

To help in this, I rearranged a heavily underused function in hb.c: hb_set_size. Given an aspect and a pixel count, it figures out the best dimensions. Apparently, it was only used by IHB ()?!)

[EDIT: rhester wants mod8 so he can be cool like Cupertino. I'll probably un-rearrange hb_set_size and make a new hb_set_anamorphic_size function in its image, that can do variable modulos, and add a MULTIPLE_8 macro somewhere.]

Code: Select all

Index: test/test.c
===================================================================
--- test/test.c	(revision 706)
+++ test/test.c	(working copy)
@@ -45,6 +45,7 @@
 static int    mux         = 0;
 static int    acodec      = 0;
 static int    pixelratio  = 0;
+static int    loosePixelratio = 0;
 static int    chapter_start = 0;
 static int    chapter_end   = 0;
 static int    chapter_markers = 0;
@@ -425,8 +426,15 @@
 
             job->deinterlace = deinterlace;
             job->grayscale   = grayscale;
-            job->pixel_ratio = pixelratio;
-
+            if (loosePixelratio)
+            {
+                job->pixel_ratio = 2;
+            }
+            else
+            {
+                job->pixel_ratio = pixelratio;
+            }
+            
             if( width && height )
             {
                 job->width  = width;
@@ -784,6 +792,7 @@
     "    -d, --deinterlace       Deinterlace video\n"
     "    -g, --grayscale         Grayscale encoding\n"
     "    -p, --pixelratio        Store pixel aspect ratio in video stream\n"
+    "    -p, --loosePixelratio   Store pixel aspect ratio with specified x*y"
 	
 	"\n"
 	
@@ -855,6 +864,7 @@
             { "deinterlace", no_argument,       NULL,    'd' },
             { "grayscale",   no_argument,       NULL,    'g' },
             { "pixelratio",  no_argument,       NULL,    'p' },
+            { "loosePixelratio", no_argument,   NULL,    'P' }, 
             { "width",       required_argument, NULL,    'w' },
             { "height",      required_argument, NULL,    'l' },
             { "crop",        required_argument, NULL,    'n' },
@@ -879,7 +889,7 @@
         int c;
 
         c = getopt_long( argc, argv,
-                         "hvuC:f:4i:o:t:Lc:ma:6:s:UN:e:E:2dgpw:l:n:b:q:S:B:r:R:Qx:TY:X:",
+                         "hvuC:f:4i:o:t:Lc:ma:6:s:UN:e:E:2dgpPw:l:n:b:q:S:B:r:R:Qx:TY:X:",
                          long_options, &option_index );
         if( c < 0 )
         {
@@ -993,6 +1003,9 @@
             case 'p':
                 pixelratio = 1;
                 break;
+            case 'P':
+                loosePixelratio = 1;
+                break;
             case 'e':
                 if( !strcasecmp( optarg, "ffmpeg" ) )
                 {
Index: libhb/hb.c
===================================================================
--- libhb/hb.c	(revision 706)
+++ libhb/hb.c	(working copy)
@@ -399,75 +399,90 @@
  * @param job Handle to hb_job_t.
  * @param aspect Desired aspect ratio. Value of -1 uses title aspect.
  * @param pixels Maximum desired pixel count.
+ * @param par If true, skip the cropping and keep-aspect-ratio stuff.
  */
-void hb_set_size( hb_job_t * job, int aspect, int pixels )
+void hb_set_size( hb_job_t * job, int aspect, int pixels, int par )
 {
     hb_title_t * title = job->title;
 
     int croppedWidth  = title->width - title->crop[2] - title->crop[3];
     int croppedHeight = title->height - title->crop[0] - title->crop[1];
-    int croppedAspect = title->aspect * title->height * croppedWidth /
-                            croppedHeight / title->width;
-    int addCrop;
-    int i, w, h;
-
-    if( aspect <= 0 )
+    
+    int croppedAspect;
+    if (par)
     {
-        /* Keep the best possible aspect ratio */
+        /* That means we're setting size for video with non-square pixels */
+        croppedAspect = croppedWidth * HB_ASPECT_BASE / croppedHeight;
         aspect = croppedAspect;
     }
+    else
+    {
+        /* We're free to change cropping and maintain display aspect ratio */
+        croppedAspect = title->aspect * title->height * croppedWidth /
+            croppedHeight / title->width;
+            
+        int addCrop;
 
-    /* Crop if necessary to obtain the desired ratio */
-    memcpy( job->crop, title->crop, 4 * sizeof( int ) );
-    if( aspect < croppedAspect )
-    {
-        /* Need to crop on the left and right */
-        addCrop = croppedWidth - aspect * croppedHeight * title->width /
-                    title->aspect / title->height;
-        if( addCrop & 3 )
+        if( aspect <= 0 )
         {
-            addCrop = ( addCrop + 1 ) / 2;
-            job->crop[2] += addCrop;
-            job->crop[3] += addCrop;
+            /* Keep the best possible aspect ratio */
+            aspect = croppedAspect;
         }
-        else if( addCrop & 2 )
+
+        /* Crop if necessary to obtain the desired ratio */
+        memcpy( job->crop, title->crop, 4 * sizeof( int ) );
+        if( aspect < croppedAspect )
         {
-            addCrop /= 2;
-            job->crop[2] += addCrop - 1;
-            job->crop[3] += addCrop + 1;
+            /* Need to crop on the left and right */
+            addCrop = croppedWidth - aspect * croppedHeight * title->width /
+                        title->aspect / title->height;
+            if( addCrop & 3 )
+            {
+                addCrop = ( addCrop + 1 ) / 2;
+                job->crop[2] += addCrop;
+                job->crop[3] += addCrop;
+            }
+            else if( addCrop & 2 )
+            {
+                addCrop /= 2;
+                job->crop[2] += addCrop - 1;
+                job->crop[3] += addCrop + 1;
+            }
+            else
+            {
+                addCrop /= 2;
+                job->crop[2] += addCrop;
+                job->crop[3] += addCrop;
+            }
         }
-        else
+        else if( aspect > croppedAspect )
         {
-            addCrop /= 2;
-            job->crop[2] += addCrop;
-            job->crop[3] += addCrop;
+            /* Need to crop on the top and bottom */
+            addCrop = croppedHeight - croppedWidth * title->aspect *
+                title->height / aspect / title->width;
+            if( addCrop & 3 )
+            {
+                addCrop = ( addCrop + 1 ) / 2;
+                job->crop[0] += addCrop;
+                job->crop[1] += addCrop;
+            }
+            else if( addCrop & 2 )
+            {
+                addCrop /= 2;
+                job->crop[0] += addCrop - 1;
+                job->crop[1] += addCrop + 1;
+            }
+            else
+            {
+                addCrop /= 2;
+                job->crop[0] += addCrop;
+                job->crop[1] += addCrop;
+            }
         }
+
     }
-    else if( aspect > croppedAspect )
-    {
-        /* Need to crop on the top and bottom */
-        addCrop = croppedHeight - croppedWidth * title->aspect *
-            title->height / aspect / title->width;
-        if( addCrop & 3 )
-        {
-            addCrop = ( addCrop + 1 ) / 2;
-            job->crop[0] += addCrop;
-            job->crop[1] += addCrop;
-        }
-        else if( addCrop & 2 )
-        {
-            addCrop /= 2;
-            job->crop[0] += addCrop - 1;
-            job->crop[1] += addCrop + 1;
-        }
-        else
-        {
-            addCrop /= 2;
-            job->crop[0] += addCrop;
-            job->crop[1] += addCrop;
-        }
-    }
-
+    
+    int i, w, h;
     /* Compute a resolution from the number of pixels and aspect */
     for( i = 0;; i++ )
     {
Index: libhb/hb.h
===================================================================
--- libhb/hb.h	(revision 706)
+++ libhb/hb.h	(working copy)
@@ -77,7 +77,7 @@
 
 void          hb_get_preview( hb_handle_t *, hb_title_t *, int,
                               uint8_t * );
-void          hb_set_size( hb_job_t *, int ratio, int pixels );
+void          hb_set_size( hb_job_t *, int ratio, int pixels, int par );
 
 /* Handling jobs */
 int           hb_count( hb_handle_t * );
Index: libhb/work.c
===================================================================
--- libhb/work.c	(revision 706)
+++ libhb/work.c	(working copy)
@@ -120,7 +120,78 @@
     	job->height=title->height-job->crop[0]-job->crop[1];
     	job->width=title->width-job->crop[2]-job->crop[3];
     }
+    else if ( job->pixel_ratio == 2 )
+    {
+        /* "Loose" anamorphic.
+            - Uses mod16-compliant dimensions,
+            - Allows users to set the width
+            - Handles ITU pixel aspects 
+        */
 
+        /* Use mod16 values for better compression */
+        job->width   = MULTIPLE_16( job->width );
+        job->height  = MULTIPLE_16( job->height );
+        job->width   = MAX( 16, job->width );
+        job->height  = MAX( 16, job->height );
+
+        /* Set up some variables to make the math easier to follow. */
+        int cropped_width = title->width - job->crop[2] - job->crop[3] ;
+        int cropped_height = title->height - job->crop[0] - job->crop[1] ;
+        int storage_aspect = cropped_width * HB_ASPECT_BASE / cropped_height;
+        int pixels = job->width * (job->width / storage_aspect * HB_ASPECT_BASE);
+
+        /* While keeping the DVD storage aspect, resize the job width and height
+           so they fit into the user's specified dimensions. */
+        hb_set_size(job, -1, pixels, 1);
+
+        if (cropped_width <= 706)
+        {
+            /* Handle ITU PARs */
+            if (title->height == 480)
+            {
+                /* It's NTSC */
+                if (title->aspect == 16)
+                {
+                    /* It's widescreen */
+                    job->pixel_aspect_width = 40;
+                    job->pixel_aspect_height = 33;
+                }
+                else
+                {
+                    /*It's 4:3 */
+                    job->pixel_aspect_width = 10;
+                    job->pixel_aspect_height = 11;
+                }
+            }
+            else if (title->height == 576)
+            {
+                /* It's PAL */
+                if(title->aspect == 16)
+                {
+                    /* It's widescreen */
+                    job->pixel_aspect_width = 16;
+                    job->pixel_aspect_height = 11;
+                }
+                else
+                {
+                    /* It's 4:3 */
+                    job->pixel_aspect_width = 12;
+                    job->pixel_aspect_height = 11;
+                }
+            }
+        }
+
+        /* Figure out what dimensions the source would display at. */
+        int source_display_width = cropped_width * ((float)job->pixel_aspect_width / (float)job->pixel_aspect_height) ;
+        
+        /* The film AR is the source's display width / cropped source height.
+           The output display width is the output height * film AR.
+           The output PAR is the output display width / output storage width. */
+        job->pixel_aspect_width = job->height * source_display_width / cropped_height;
+        job->pixel_aspect_height = job->width;
+
+    }
+    
 	/* Keep width and height within these boundaries */
 	if (job->maxHeight && (job->height > job->maxHeight) )
 	{
 	
realityking
Veteran User
Posts: 680
Joined: Tue Apr 24, 2007 12:36 pm

Post by realityking »

I know that quality is supposed to be better if the resolution is mod16 but how much is this in reality? Just wondering what to use in the future ;)
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

The difference is minor.

On one sample chapter I just tested, 1000kbps with the current anamorphic gave me 59.22% quality, whereas the same bitrate with mod16-corrected dimensions gave me 59.51% quality.
saintdev
Enlightened
Posts: 146
Joined: Wed Dec 20, 2006 4:17 am

Post by saintdev »

realityking wrote:I know that quality is supposed to be better if the resolution is mod16 but how much is this in reality? Just wondering what to use in the future ;)
It also gets rid of that ugly green bar in VLC.
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

Post by risck »

Just wondering if this patch is still apply-able with the current trunk... I recently trashed my old build dir... well the drive had some corruption...

If it is I'm thinking of spinning a new build with the mod-16 to compare speeds... along with a few other tweaks.
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

Doubtful that it's still applicable, though one of the ones in the thread might be given sufficiently fuzzy patching. Lots of shifting around in work.c and test.c.

I'm not done yet, anyways. I've got newer code that's more up to date, locally, but it still has some issues with edge cases.
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

r960

Post by risck »

Glad to see this had landed :)

On a side note x264 has implement multithreaded me=esa not that esa is better the uhm but for those crazy nutty people who does use esa from time to time our encode times might improve slightly soon :)
saintdev
Enlightened
Posts: 146
Joined: Wed Dec 20, 2006 4:17 am

Re: r960

Post by saintdev »

risck wrote:Glad to see this had landed :)

On a side note x264 has implement multithreaded me=esa not that esa is better the uhm but for those crazy nutty people who does use esa from time to time our encode times might improve slightly soon :)
Actually it hasn't. That was a completely errant commit by myself.

As jbrjake has said he has much newer code locally, but feels the need to keep it all to himself ;)
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Re: r960

Post by jbrjake »

saintdev wrote:As jbrjake has said he has much newer code locally, but feels the need to keep it all to himself ;)
I think I'm finally close to done with this loose anamorphic stuff. Only problem I see right now is that if the sar values are too big, and don't reduce to smaller than 256, then ffmpeg screws up the video stream sar. this makes it play *really* distorted in vlc. Works fine in QuickTime, and the problem is limited to ffmpeg -- xvid and x264 work fine. I can't imagine there are that many people out there who A: care about anamorphic at arbitrary widths, B: only use ffmpeg's encoder, and C: don't use QuickTime.

I've added an optional argument to the -P flag: the modulus you want. So there you go, rhester -- mod 8 away! :-) For some reason, at least in Darwin, I can't get optional arguments to work with short option names. So -P 16 doesn't work. You've gotta do --loosePixelratio=16 ...not sure what that's about. But the same thing holds for all the flags with optional arguments. Also, for various reasons, this doesn't include raw dimensions. If you want weird numbers that won't compress efficiently, use the old anamorphic function.

Be aware that the way this anamorphic method works can lead to some counter-intuitive results.

For example, I have a movie that, after cropping, is 710*366. If you use the default modulus of 16, loose anamorphic gives you dimensions of 704*368. But if you choose a mod of 8, you get 704*360. Why? Because this method focuses on maintaining the storage aspect ratio. 704/360 is closer to 710/366 than 704/368 is, so when 360 becomes an option (by using mod8), the code will gravitate to that -- even though 368 is more lines. Also, I've set it to tend towards scaling down over scaling up the number of lines.

Anyways, here's the code.

Code: Select all

Index: test/test.c
===================================================================
--- test/test.c	(revision 1018)
+++ test/test.c	(working copy)
@@ -53,6 +53,8 @@
 static int    mux         = 0;
 static int    acodec      = 0;
 static int    pixelratio  = 0;
+static int    loosePixelratio = 0;
+static int    modulus       = 0;
 static int    chapter_start = 0;
 static int    chapter_end   = 0;
 static int    chapter_markers = 0;
@@ -449,8 +451,18 @@
 
             job->deinterlace = deinterlace;
             job->grayscale   = grayscale;
-            job->pixel_ratio = pixelratio;
-
+            if (loosePixelratio)
+            {
+                job->pixel_ratio = 2;
+                if (modulus)
+                {
+                    job->modulus = modulus;
+                }
+            }
+            else
+            {
+                job->pixel_ratio = pixelratio;
+            }
             /* Add selected filters */
             job->filters = hb_list_init();
             if( detelecine )
@@ -874,6 +886,10 @@
      "          <L:R:T:B:SB:MP>   (default 1:1:4:4:0:0)\n"
     "    -g, --grayscale         Grayscale encoding\n"
     "    -p, --pixelratio        Store pixel aspect ratio in video stream\n"
+    "    -p, --loosePixelratio   Store pixel aspect ratio with specified width\n"
+    "           <modulus>        Takes as optional argument what number you want\n"
+    "                            the dimensions to divide cleanly by (default 16)\n"
+    
 	
 	"\n"
 	
@@ -949,6 +965,7 @@
             { "detelecine",  optional_argument, NULL,    '9' },
             { "grayscale",   no_argument,       NULL,    'g' },
             { "pixelratio",  no_argument,       NULL,    'p' },
+            { "loosePixelratio", optional_argument,   NULL,    'P' },
             { "width",       required_argument, NULL,    'w' },
             { "height",      required_argument, NULL,    'l' },
             { "crop",        required_argument, NULL,    'n' },
@@ -973,7 +990,7 @@
         int c;
 
         c = getopt_long( argc, argv,
-                         "hvuC:f:4i:o:t:Lc:ma:6:s:UFN:e:E:2d789gpw:l:n:b:q:S:B:r:R:Qx:TY:X:",
+                         "hvuC:f:4i:o:t:Lc:ma:6:s:UFN:e:E:2d789gpP::w:l:n:b:q:S:B:r:R:Qx:TY:X:",
                          long_options, &option_index );
         if( c < 0 )
         {
@@ -1115,6 +1132,13 @@
             case 'p':
                 pixelratio = 1;
                 break;
+            case 'P':
+                loosePixelratio = 1;
+                if( optarg != NULL )
+                {
+                    modulus = atoi( optarg );
+                }
+                break;
             case 'e':
                 if( !strcasecmp( optarg, "ffmpeg" ) )
                 {
Index: libhb/hb.c
===================================================================
--- libhb/hb.c	(revision 1018)
+++ libhb/hb.c	(working copy)
@@ -427,6 +427,156 @@
 }
 
 /**
+ * Calculates job width and height for anamorphic content.
+ * @param job Handle to hb_job_t.
+ */
+void hb_set_anamorphic_size( hb_job_t * job)
+{
+    hb_title_t * title = job->title;
+
+    /* "Loose" anamorphic.
+        - Uses mod16-compliant dimensions,
+        - Allows users to set the width
+        - Handles ITU pixel aspects
+    */
+    
+    /* Set up some variables to make the math easier to follow. */
+    int cropped_width = title->width - job->crop[2] - job->crop[3] ;
+    int cropped_height = title->height - job->crop[0] - job->crop[1] ;
+    int storage_aspect = cropped_width * 10000 / cropped_height;        
+        
+    /* Gotta handle bounding dimensions differently
+       than for non-anamorphic encodes:
+       If the width is too big, just reset it with no rescaling.
+       Instead of using the aspect-scaled job height,
+       we need to see if the job width divided by the storage aspect
+       is bigger than the max. If so, set it to the max (this is sloppy).
+       If not, set job height to job width divided by storage aspect.
+    */
+    if ( job->maxWidth && (job->maxWidth < job->width) )
+        job->width = job->maxWidth;
+        
+    if ( job->maxHeight && (job->maxHeight < (job->width / storage_aspect * 10000)) )
+    {
+        job->height = job->maxHeight;
+    }
+    else
+    {
+        job->height = job->width * 10000 / storage_aspect;
+    }
+        
+    /* Time to get picture dimensions that divide cleanly.
+       These variables will store temporary dimensions as we iterate. */
+    int i, w, h, mod;
+
+    /* In case the user specified a modulus, use it */
+    if (job->modulus)
+        mod = job->modulus;
+    else
+        mod = 16;
+        
+    /* Iterate through multiples of mod to find one close to job->width. */
+    for( i = 1;; i++ )
+    {
+        w = mod * i;
+        
+        if (w < job->width)
+        {
+            if ( ( job->width - w ) <= ( mod / 2 ) )
+                /* We'll take a width that's
+                   smaller, but close enough. */
+                break;
+        }
+        if (w == job->width)
+            /* Mod 16 dimensions, how nice! */
+            break;
+        if( w > job->width )
+        {
+            if ( ( w - job->width ) < (mod/2) )
+                /* We'll take a width that's bigger, if we have to. */
+                break;
+        }
+    }
+    job->width  = mod * (i);
+    
+    /* Now do the same for a mod-friendly value near job->height. */
+    for( i = 1;; i++)
+    {
+        h = i * mod;
+        
+        if (h < job->height)
+            {
+                if ( ( job->height - h ) <= ( mod / 2 ))
+                    /* Go with a smaller height,
+                       if it's close enough.    */
+                    break;
+            }
+        if (h == job->height)
+            /* Mod 16 dimensions, how nice! */
+            break;
+            
+        if ( h > job->height)
+        {
+            if ( ( h - job->height ) < ( mod / 2 ))
+                /* Use a taller height if necessary */
+                break;
+        }
+    }
+    job->height = mod  * (i);
+    
+    if (cropped_width <= 706)
+    {
+        /* Handle ITU PARs */
+        if (title->height == 480)
+        {
+            /* It's NTSC */
+            if (title->aspect == 16)
+            {
+                /* It's widescreen */
+                job->pixel_aspect_width = 40;
+                job->pixel_aspect_height = 33;
+            }
+            else
+            {
+                /* It's 4:3 */
+                job->pixel_aspect_width = 10;
+                job->pixel_aspect_height = 11;
+            }
+        }
+        else if (title->height == 576)
+        {
+            /* It's PAL */
+            if(title->aspect == 16)
+            {
+                /* It's widescreen */
+                job->pixel_aspect_width = 16;
+                job->pixel_aspect_height = 11;
+            }
+            else
+            {
+                /* It's 4:3 */
+                job->pixel_aspect_width = 12;
+                job->pixel_aspect_height = 11;
+            }
+        }
+    }
+
+    /* Figure out what dimensions the source would display at. */
+    int source_display_width = cropped_width * ((float)job->pixel_aspect_width / (float)job->pixel_aspect_height) ;
+   
+    /* The film AR is the source's display width / cropped source height.
+       The output display width is the output height * film AR.
+       The output PAR is the output display width / output storage width. */
+    job->pixel_aspect_width = job->height * source_display_width / cropped_height;
+    job->pixel_aspect_height = job->width;
+    
+    /* While x264 is smart enough to reduce fractions on its own, libavcodec
+       needs some help with the math, so lose superfluous factors.            */
+    hb_reduce( &job->pixel_aspect_width, &job->pixel_aspect_height,
+               job->pixel_aspect_width, job->pixel_aspect_height );
+}
+
+/**
  * Calculates job width, height, and cropping parameters.
  * @param job Handle to hb_job_t.
  * @param aspect Desired aspect ratio. Value of -1 uses title aspect.
Index: libhb/hb.h
===================================================================
--- libhb/hb.h	(revision 1018)
+++ libhb/hb.h	(working copy)
@@ -78,6 +78,7 @@
 void          hb_get_preview( hb_handle_t *, hb_title_t *, int,
                               uint8_t * );
 void          hb_set_size( hb_job_t *, int ratio, int pixels );
+void          hb_set_anamorphic_size( hb_job_t * );
 
 /* Handling jobs */
 int           hb_count( hb_handle_t * );
Index: libhb/work.c
===================================================================
--- libhb/work.c	(revision 1018)
+++ libhb/work.c	(working copy)
@@ -128,16 +128,27 @@
     	job->height=title->height-job->crop[0]-job->crop[1];
     	job->width=title->width-job->crop[2]-job->crop[3];
     }
+    else if ( job->pixel_ratio == 2 )
+    {
 
-	/* Keep width and height within these boundaries */
-	if (job->maxHeight && (job->height > job->maxHeight) )
+        /* While keeping the DVD storage aspect, resize the job width and height
+           so they fit into the user's specified dimensions. */
+        hb_set_anamorphic_size(job);
+    }
+   
+
+	/* Keep width and height within these boundaries,
+	   but ignore for "loose" anamorphic encodes, for
+	   which this stuff is covered in the pixel_ratio
+	   section right above.*/
+	if (job->maxHeight && (job->height > job->maxHeight) && (job->pixel_ratio != 2))
 	{
 		job->height = job->maxHeight;
 		hb_fix_aspect( job, HB_KEEP_HEIGHT );
 		hb_log("Height out of bounds, scaling down to %i", job->maxHeight);
 		hb_log("New dimensions %i * %i", job->width, job->height);
 	}
-	if (job->maxWidth && (job->width > job->maxWidth) )
+	if (job->maxWidth && (job->width > job->maxWidth) && (job->pixel_ratio != 2))
 	{
 		job->width = job->maxWidth;
 		hb_fix_aspect( job, HB_KEEP_WIDTH );   
Index: libhb/common.h
===================================================================
--- libhb/common.h	(revision 1018)
+++ libhb/common.h	(working copy)
@@ -27,6 +27,7 @@
 
 #define EVEN( a )        ( (a) + ( (a) & 1 ) )
 #define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) )
+#define MULTIPLE_MOD( a, b ) ( b * ( ( (a) + (b / 2) ) / b ) )
 
 #define HB_DVD_READ_BUFFER_SIZE 2048
 
@@ -139,6 +140,7 @@
     int             pixel_ratio;
     int             pixel_aspect_width;
     int             pixel_aspect_height;
+    int             modulus;
 	int				maxWidth;
 	int				maxHeight;
 
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

Re: r960

Post by risck »

jbrjake wrote:Anyways, here's the code.
AHHH.... copy and past from my browser to patch file fails... looks like the browser changed the formating a little to much now everything collides :( I now have something to do tonight... can't wait to give this baby a spin :)
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

Re: r960

Post by risck »

jbrjake wrote:

Code: Select all

@@ -874,6 +886,10 @@
      "          <L:R:T:B:SB:MP>   (default 1:1:4:4:0:0)\n"
     "    -g, --grayscale         Grayscale encoding\n"
     "    -p, --pixelratio        Store pixel aspect ratio in video stream\n"
+    "    -p, --loosePixelratio   Store pixel aspect ratio with specified width\n"
+    "           <modulus>        Takes as optional argument what number you want\n"
+    "                            the dimensions to divide cleanly by (default 16)\n"
+    
 	
 	"\n"
 	

Question:
Shouldn't that be

Code: Select all

+    "    -P, --loosePixelratio   Store pixel aspect ratio with specified width\n"
The 'p' should be capitalized right? Might that resolve your -P 8 issue?

After cleaning up what ever my browser did the patch I think I've finally have a cleaned version of the patch to build from :)

Now I used the build and did two back to back rips on the same DVD/chapter/title... noticed a few issues which makes me think I missed something on my browser cleanup

Code: Select all

*** Zero check failed in ifo_read.c:2015
    for vts_attributes->vtstt_audio_attr[i] = 0x04c56e6500000000
*** Zero check failed in ifo_read.c:565
    for vtsi_mat->vts_audio_attr[i] = 0x04c56e6500000000
Also it appears, based on the output stats, -p produces a better image... buy the numbers... or my very very limited and cured understanding of the outputted CLI stats.
Last edited by risck on Wed Oct 17, 2007 4:41 pm, edited 1 time in total.
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Re: r960

Post by jbrjake »

risck wrote:The 'p' should be capitalized right?
Yes.
Might that resolve your -P 8 issue?
No...changing documentation is not going to change how the program works.

Zero check failures have nothing to do with this patch.
Also it appears, based on the output stats, -p produces a better image... buy the numbers... or my very very limited and cured understanding of the outputted CLI stats.
You can't make blanket statements like that. It entirely depends on what resolution it ends up using, which depends on whether the mod16 values are higher or lower than the source, which depends on the cropping, which varies with every single source. If instead of 710*366 (259,860 pix) with -p, I get 704*368 with -P (259,072 pix), then the same bitrate will give me higher quality because it's a smaller resolution.

Are you going to share the stats?
eddyg
Veteran User
Posts: 798
Joined: Mon Apr 23, 2007 3:34 am

Post by eddyg »

Sorry about the delay - looks good to me. Would have thought that the nearest size could be calculated without iteration, however this works, and is fast - so who cares.

Cheers, Ed.
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

eddyg wrote:Would have thought that the nearest size could be calculated without iteration
Yeah, probably...I just based what I was doing on the current code titer wrote, to handle mod16 dimensions.

Anyway, I checked this work in as rev 1029. I made a few minor changes from the version presented above -- for example, I included a check in test.c to set the width to title width minus cropping when the user doesn't provide one. This is for 4:3 stuff, where if we didn't reset the width, it'd start at 640 and we'd be scaling down.
eddyg
Veteran User
Posts: 798
Joined: Mon Apr 23, 2007 3:34 am

Post by eddyg »

Here is an example without using iterations, is this the sort of thing you had in mind, rounding up and down?

Code: Select all

#include <stdio.h>

int main()
{
    int i, n, mod, mask;
    
    mod = 16;
    mask = mod - 1;

    for(i = 1; i < 100; i++) {
        if (i & (mod >> 1)) {
            /*
             * Round up
             */
            n = (i & ~mask) + mod;
        } else {
            /*
             * Round down
             */
            n = i & ~mask;
        }
        printf("Output for %d: %d = %d\n", mod, i, n);
    }
}
Which produces:

Code: Select all

Output: 1 = 0
Output: 2 = 0
Output: 3 = 0
Output: 4 = 0
Output: 5 = 0
Output: 6 = 0
Output: 7 = 0
Output: 8 = 16
Output: 9 = 16
Output: 10 = 16
Output: 11 = 16
Output: 12 = 16
Output: 13 = 16
Output: 14 = 16
Output: 15 = 16
Output: 16 = 16
Output: 17 = 16
Output: 18 = 16
Output: 19 = 16
Output: 20 = 16
Output: 21 = 16
Output: 22 = 16
Output: 23 = 16
Output: 24 = 32
Output: 25 = 32
Output: 26 = 32
Output: 27 = 32
Output: 28 = 32
Output: 29 = 32
Output: 30 = 32
Output: 31 = 32
Output: 32 = 32
Output: 33 = 32
Output: 34 = 32
Output: 35 = 32
Output: 36 = 32
Output: 37 = 32
Output: 38 = 32
Output: 39 = 32
Output: 40 = 48
Output: 41 = 48
Output: 42 = 48
Output: 43 = 48
Output: 44 = 48
Output: 45 = 48
Output: 46 = 48
Output: 47 = 48
Output: 48 = 48
Output: 49 = 48
Output: 50 = 48
Output: 51 = 48
Output: 52 = 48
Output: 53 = 48
Output: 54 = 48
Output: 55 = 48
Output: 56 = 64
Output: 57 = 64
Output: 58 = 64
Output: 59 = 64
Output: 60 = 64
Output: 61 = 64
Output: 62 = 64
Output: 63 = 64
Output: 64 = 64
Output: 65 = 64
Output: 66 = 64
Output: 67 = 64
Output: 68 = 64
Output: 69 = 64
Output: 70 = 64
Output: 71 = 64
Output: 72 = 80
Output: 73 = 80
Output: 74 = 80
Output: 75 = 80
Output: 76 = 80
Output: 77 = 80
Output: 78 = 80
Output: 79 = 80
Output: 80 = 80
Output: 81 = 80
Output: 82 = 80
Output: 83 = 80
Output: 84 = 80
Output: 85 = 80
Output: 86 = 80
Output: 87 = 80
Output: 88 = 96
Output: 89 = 96
Output: 90 = 96
Output: 91 = 96
Output: 92 = 96
Output: 93 = 96
Output: 94 = 96
Output: 95 = 96
Output: 96 = 96
Output: 97 = 96
Output: 98 = 96
Output: 99 = 96
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

That for loop you're using to demonstrate how it'd work threw me for a second, but yeah, I see.

So it'd be like this?

Code: Select all

        /* In case the user specified a modulus, use it */
        if (job->modulus)
            mod = job->modulus;
        else
            mod = 16;

        int mask = mod - 1;

        if (job->width & (mod >> 1)) 
        {
            /*
             * Round up
             */
            job->width = (job->width & ~mask) + mod;
        }
        else
        {
            /*
             * Round down
             */
            job->width = job->width & ~mask;
        }

        if (job->height & (mod >> 1)) 
        {
            /*
             * Round up
             */
            job->height = (job->height & ~mask) + mod;
        }
        else
        {
            /*
             * Round down
             */
            job->height = job->height & ~mask;
        }
eddyg
Veteran User
Posts: 798
Joined: Mon Apr 23, 2007 3:34 am

Post by eddyg »

Exactly.
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

Re: r960

Post by risck »

jbrjake wrote: No...changing documentation is not going to change how the program works.
I was a little tired when I wrote that just wasn't thinking :)
jbrjake wrote:Zero check failures have nothing to do with this patch.
Didn't think so... but like like I said I was a little tired writing that post... and trilled about this patch... I wasn't sure if I didn't patch something correctly...

jbrjake wrote:
risck wrote: Also it appears, based on the output stats, -p produces a better image... buy the numbers... or my very very limited and cured understanding of the outputted CLI stats.
You can't make blanket statements like that. It entirely depends on what resolution it ends up using, which depends on whether the mod16 values are higher or lower than the source, which depends on the cropping, which varies with every single source. If instead of 710*366 (259,860 pix) with -p, I get 704*368 with -P (259,072 pix), then the same bitrate will give me higher quality because it's a smaller resolution.

Are you going to share the stats?
Based on the subjective eye test I can't tell the difference between the two encodes so thats good. I was making the poor, blanket, statment based on my understanding of the outputted stat info. Which I'm is extremely poor, my understanding of those stats that is :? and yes the difference between the SSIM and PSNR is so insignificant its was pointless to even mention. :oops:

The stats (Stranger than Fiction-- chapter 3):

Code: Select all

-P
Encoding: task 1 of 1, 0.00 %x264 [info]: using SAR=107/90
x264 [info]: using cpu capabilities: MMX MMXEXT SSE SSE2 
No accelerated IMDCT transform found
Muxing: 0.00 %x264 [info]: slice I:67    Avg QP:12.93  size: 63605  PSNR Mean Y:50.27 U:51.65 V:51.71 Avg:50.69 Global:50.66
x264 [info]: slice P:1896  Avg QP:14.89  size: 27356  PSNR Mean Y:47.78 U:49.46 V:49.53 Avg:48.28 Global:48.17
x264 [info]: slice B:3857  Avg QP:16.74  size:  7868  PSNR Mean Y:46.61 U:49.12 V:49.21 Avg:47.30 Global:47.22
x264 [info]: mb I  I16..4: 29.8%  0.0% 70.2%
x264 [info]: mb P  I16..4:  6.1%  0.0% 11.4%  P16..4: 34.1% 30.5% 13.7%  1.3%  1.2%    skip: 1.7%
x264 [info]: mb B  I16..4:  0.6%  0.0%  0.8%  B16..8: 30.0%  3.6% 10.0%  direct:11.6%  skip:43.5%
x264 [info]: direct mvs  spatial:99.9%  temporal:0.1%
x264 [info]: ref P  78.9% 12.9%  8.2%
x264 [info]: ref B  89.4%  7.3%  3.3%
x264 [info]: SSIM Mean Y:0.9896057
x264 [info]: PSNR Mean Y:47.034 U:49.264 V:49.342 Avg:47.659 Global:47.535 kb/s:2849.89

Code: Select all

-p
Muxing: 0.00 %x264 [info]: slice I:67    Avg QP:12.94  size: 62895  PSNR Mean Y:50.36 U:52.05 V:52.22 Avg:50.87 Global:50.84
x264 [info]: slice P:1890  Avg QP:14.89  size: 27028  PSNR Mean Y:47.81 U:49.81 V:49.94 Avg:48.39 Global:48.27
x264 [info]: slice B:3863  Avg QP:16.73  size:  7623  PSNR Mean Y:46.66 U:49.50 V:49.65 Avg:47.42 Global:47.32
x264 [info]: mb I  I16..4: 29.8%  0.0% 70.2%
x264 [info]: mb P  I16..4:  5.6%  0.0% 11.1%  P16..4: 35.7% 29.9% 13.3%  1.3%  1.2%    skip: 2.0%
x264 [info]: mb B  I16..4:  0.5%  0.0%  0.7%  B16..8: 30.4%  3.3%  8.8%  direct:10.8%  skip:45.3%
x264 [info]: direct mvs  spatial:99.9%  temporal:0.1%
x264 [info]: ref P  78.5% 13.1%  8.4%
x264 [info]: ref B  89.4%  7.3%  3.3%
x264 [info]: SSIM Mean Y:0.9899099
x264 [info]: PSNR Mean Y:47.073 U:49.631 V:49.773 Avg:47.777 Global:47.638 kb/s:2792.88
I plan on encoding my fresh copy of Transformers tonight... once with -p and once with -P... I will post those stats in the benchmark thread once the encode cycle ends if you like...
Cavalicious
Moderator
Posts: 1804
Joined: Mon Mar 26, 2007 12:07 am

Post by Cavalicious »

My -p stats for Transformers:

Code: Select all

x264 [info]: slice I:2819  Avg QP:18.48  size: 36079  PSNR Mean Y:44.62 U:45.84 V:46.46 Avg:44.99 Global:43.99
x264 [info]: slice P:112398 Avg QP:20.66  size: 19666  PSNR Mean Y:43.85 U:45.00 V:45.73 Avg:44.23 Global:43.59
x264 [info]: slice B:90958 Avg QP:22.13  size:  7649  PSNR Mean Y:43.35 U:44.83 V:45.97 Avg:43.79 Global:42.74
x264 [info]: mb I  I16..4: 33.5%  0.0% 66.5%
x264 [info]: mb P  I16..4: 12.9%  0.0% 17.0%  P16..4: 30.5% 20.1% 12.1%  0.0%  0.0%    skip: 7.3%
x264 [info]: mb B  I16..4:  1.0%  0.0%  2.6%  B16..8: 29.4%  2.8%  7.9%  direct:14.3%  skip:42.0%
x264 [info]: ref P  81.5% 11.6%  6.9%
x264 [info]: ref B  86.2%  9.2%  4.6%
x264 [info]: SSIM Mean Y:0.9818379
x264 [info]: PSNR Mean Y:43.642 U:44.937 V:45.847 Avg:44.044 Global:43.197 kb/s:2798.24
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

I'm not sure what you guys are trying to demonstrate...

Like I said, this is entirely dependent on resolution. It's a matter of cropping and whether the closest mod-friendly values are higher or lower.

Pasting a bunch of metrics without including that info is pointless.
Cavalicious
Moderator
Posts: 1804
Joined: Mon Mar 26, 2007 12:07 am

Post by Cavalicious »

It was Monkey see Monkey do on my part. :?
risck
Novice
Posts: 51
Joined: Mon Apr 23, 2007 1:20 am

Post by risck »

jbrjake wrote:I'm not sure what you guys are trying to demonstrate...
I'm not trying to demonstrate a thing... you asked if I was going to share the sats so I posted what I was comparing... the SSIM mean's and PSNR mean's. Which I would assume is probably the best, objective, way to compare quality. Yes, like you said it's a matter of cropping, whether the closest mod-friendly values are higher or lower. However I'm not going sit down and figure that out before I encode in order to pick the best pixel ratio. I'm going to run a few test and compare the results.


My criteria for this comparison is simple, using the exact same source material and settings (with the exception of pixel ratio and output name) compare fps, SSIM mean and PSNR mean. I think all three are fairly good data points to objectively compare.

So its fugi apple versus gala apple. :wink:

BTW: I know your against the idea of having a set encode setting as you should make changes based on source... and you would also toss bitrate and quantizer into my data point comparison table.
jbrjake
Veteran User
Posts: 4805
Joined: Wed Dec 13, 2006 1:38 am

Post by jbrjake »

risck wrote:However I'm not going sit down and figure that out before I encode in order to pick the best pixel ratio.
All I'm asking you to do is include the dimensions the video track is stored at for -p and -P respectively. That context would make your metrics useful. Without that, they don't really say anything at all. I don't understand what's difficult about sharing the resolution with everyone...

Again, I'm not sure what this comparison is supposed to reveal. This code was about using dimensions that divide cleanly by a given number, more precisely matching the intended aspect ratio for material that uses ITU pars, and letting people fool around with anamorphic at arbitrary sizes. I tried to make it very clear earlier in the thread, when realityking asked, that any affect on quality will be negligible.
Post Reply