diff options
-rw-r--r-- | libhb/common.h | 2 | ||||
-rw-r--r-- | libhb/hb.c | 150 | ||||
-rw-r--r-- | libhb/hb.h | 1 | ||||
-rw-r--r-- | libhb/work.c | 16 | ||||
-rw-r--r-- | test/test.c | 43 |
5 files changed, 203 insertions, 9 deletions
diff --git a/libhb/common.h b/libhb/common.h index e71959142..1cf6cdb59 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -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; diff --git a/libhb/hb.c b/libhb/hb.c index a53bd1f4a..6b108bdf0 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -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. diff --git a/libhb/hb.h b/libhb/hb.h index 6f8af2aee..be629505f 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -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 * ); diff --git a/libhb/work.c b/libhb/work.c index 72d12d75a..22e081532 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -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 ); diff --git a/test/test.c b/test/test.c index b9b0c4254..2d84c6624 100644 --- a/test/test.c +++ b/test/test.c @@ -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" ) ) { |