OSDN Git Service

"Loose" anamorphic:
authorjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 16 Oct 2007 19:00:41 +0000 (19:00 +0000)
committerjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Tue, 16 Oct 2007 19:00:41 +0000 (19:00 +0000)
- Scales the storage frame size to arbitrary widths, like 640 for the iPod.
- Uses dimensions that divide cleanly by an arbitrary number (default: 16) and adjusts the SAR to match
- Uses ITU PAR values when the video is meant to be overscanned ( 7+ pixels cropped on left+right)

git-svn-id: svn://localhost/HandBrake/trunk@1029 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/common.h
libhb/hb.c
libhb/hb.h
libhb/work.c
test/test.c

index e719591..1cf6cdb 100644 (file)
@@ -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 @@ struct hb_job_s
     int             pixel_ratio;
     int             pixel_aspect_width;
     int             pixel_aspect_height;
+    int             modulus;
        int                             maxWidth;
        int                             maxHeight;
 
index a53bd1f..6b108bd 100644 (file)
@@ -427,6 +427,156 @@ void hb_get_preview( hb_handle_t * h, hb_title_t * title, int picture,
 }
 
 /**
+ * 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 6f8af2a..be62950 100644 (file)
@@ -78,6 +78,7 @@ hb_list_t   * hb_get_titles( hb_handle_t * );
 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 72d12d7..22e0815 100644 (file)
@@ -128,16 +128,26 @@ static void do_job( hb_job_t * job, int cpu_count )
        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 )
+    {
+
+        /* 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 */
-       if (job->maxHeight && (job->height > job->maxHeight) )
+       /* 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 b9b0c42..2d84c66 100644 (file)
@@ -53,6 +53,8 @@ static int    abitrate    = 0;
 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 @@ static int HandleEvents( hb_handle_t * h )
 
             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 )
@@ -484,16 +496,23 @@ static int HandleEvents( hb_handle_t * h )
                 job->width = width;
                 hb_fix_aspect( job, HB_KEEP_WIDTH );
             }
-            else if( height )
+            else if( height && !loosePixelratio)
             {
                 job->height = height;
                 hb_fix_aspect( job, HB_KEEP_HEIGHT );
             }
-            else if( !width && !height && !pixelratio )
+            else if( !width && !height && !pixelratio && !loosePixelratio )
             {
                 hb_fix_aspect( job, HB_KEEP_WIDTH );
             }
-
+            else if (!width && loosePixelratio)
+            {
+                /* Default to full width when one isn't specified for loose anamorphic */
+                job->width = title->width - job->crop[2] - job->crop[3];
+                /* The height will be thrown away in hb.c but calculate it anyway */
+                hb_fix_aspect( job, HB_KEEP_WIDTH );
+            }
+            
             if( vquality >= 0.0 && vquality <= 1.0 )
             {
                 job->vquality = vquality;
@@ -874,6 +893,10 @@ static void ShowHelp()
      "          <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 +972,7 @@ static int ParseOptions( int argc, char ** argv )
             { "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 +997,7 @@ static int ParseOptions( int argc, char ** argv )
         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 +1139,13 @@ static int ParseOptions( int argc, char ** argv )
             case 'p':
                 pixelratio = 1;
                 break;
+            case 'P':
+                loosePixelratio = 1;
+                if( optarg != NULL )
+                {
+                    modulus = atoi( optarg );
+                }
+                break;
             case 'e':
                 if( !strcasecmp( optarg, "ffmpeg" ) )
                 {