All pastes #2013393 Raw Edit

Someone

public diff v1 · immutable
#2013393 ·published 2010-12-08 00:30 UTC
rendered paste body
diff --git a/common/common.c b/common/common.cindex 6c88556..90307f6 100644--- a/common/common.c+++ b/common/common.c@@ -25,6 +25,7 @@  *****************************************************************************/  #include "common.h"+#include "encoder/set.h"  #include <stdarg.h> #include <ctype.h>@@ -66,7 +67,7 @@ void x264_param_default( x264_param_t *param )     param->vui.i_chroma_loc= 0;  /* left center */     param->i_fps_num       = 25;     param->i_fps_den       = 1;-    param->i_level_idc     = -1;+    param->i_level_idc     = X264_LEVEL_IDC_AUTO;     param->i_slice_max_size = 0;     param->i_slice_max_mbs = 0;     param->i_slice_count = 0;@@ -428,15 +429,15 @@ int x264_param_apply_profile( x264_param_t *param, const char *profile )         return 0;  #if BIT_DEPTH > 8-    if( !strcasecmp( profile, "baseline" ) || !strcasecmp( profile, "main" ) ||-        !strcasecmp( profile, "high" ) )+    if( x264_get_profile( profile ) == PROFILE_BASELINE || x264_get_profile( profile == PROFILE_MAIN ) ||+        x264_get_profile( profile ) == PROFILE_HIGH )     {         x264_log( NULL, X264_LOG_ERROR, "%s profile doesn't support a bit depth of %d.\n", profile, BIT_DEPTH );         return -1;     } #endif -    if( !strcasecmp( profile, "baseline" ) )+    if( x264_get_profile( profile ) == PROFILE_BASELINE )     {         param->analyse.b_transform_8x8 = 0;         param->b_cabac = 0;@@ -454,12 +455,13 @@ int x264_param_apply_profile( x264_param_t *param, const char *profile )             return -1;         }     }-    else if( !strcasecmp( profile, "main" ) )+    else if( x264_get_profile( profile ) == PROFILE_MAIN )     {         param->analyse.b_transform_8x8 = 0;         param->i_cqm_preset = X264_CQM_FLAT;     }-    else if( !strcasecmp( profile, "high" ) || !strcasecmp( profile, "high10" ) )+    else if( x264_get_profile( profile ) == PROFILE_HIGH || +        x264_get_profile( profile ) == PROFILE_HIGH10 )     {         /* Default */     }@@ -477,6 +479,66 @@ int x264_param_apply_profile( x264_param_t *param, const char *profile )     return 0; } +int x264_param_apply_level( x264_param_t *param, const char *profile )+{+    int level_idc = param->i_level_idc;+    if( level_idc == X264_LEVEL_IDC_AUTO )+        return 0;++    int prof = BIT_DEPTH == 8 ? PROFILE_HIGH : PROFILE_HIGH10;+    prof = x264_get_profile( profile );++    const x264_level_t *l = x264_get_level( level_idc );+    if( !l )+    {+        x264_log( NULL, X264_LOG_ERROR, "Invalid level_idc: %d\n", level_idc );+        return -1;+    }++    char level_name[5];+    snprintf( level_name, sizeof(level_name), "%d.%d", level_idc/10, level_idc%10 );+    if( level_idc == 9 )+        strcpy( level_name, "1b" );+    int cbp_factor = prof==PROFILE_HIGH10 ? 12 :+                     prof==PROFILE_HIGH ? 5 : 4;+    int mb_size = 384*BIT_DEPTH/8;+    int mbs = ((param->i_width+15)/16) * ((param->i_height+15)/16);+    while( 1 )+    {+        int num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0;+        int max_dec_frame_buffering = X264_MIN(X264_REF_MAX, X264_MAX4(param->i_frame_reference, 1 + num_reorder_frames, +                                      param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size));+        int dpb = max_dec_frame_buffering * mbs * mb_size;++        if( dpb <= l->dpb )+            break;++        if( max_dec_frame_buffering == 4 && param->i_bframe_pyramid )+            param->i_bframe_pyramid = 0;+        else if( max_dec_frame_buffering == 2 && param->i_bframe )+            param->i_bframe = 0;+        else if( max_dec_frame_buffering == 1 )+        {+            x264_log( NULL, X264_LOG_ERROR, "Impossible DPB size %d required by level %s.  Lowest\n", l->dpb, level_name );+            x264_log( NULL, X264_LOG_ERROR, "possible is %d; try a higher level or lower resolution.\n", dpb );+            return -1;+        }+        else if( param->i_dpb_size > param->i_frame_reference )+            param->i_dpb_size--;+        else+            param->i_frame_reference--;+    }++#define LIMIT( name, limit, val ) \+    if( (val) > (limit) || (val) <= 0 ) \+        val = limit;++    LIMIT( "VBV bitrate", l->bitrate * cbp_factor / 4, param->rc.i_vbv_max_bitrate );+    LIMIT( "VBV buffer", l->cpb * cbp_factor / 4, param->rc.i_vbv_buffer_size );+    LIMIT( "MV range", l->mv_range, param->analyse.i_mv_range );+    return 0;+}+ static int parse_enum( const char *arg, const char * const *names, int *dst ) {     for( int i = 0; names[i]; i++ )diff --git a/encoder/encoder.c b/encoder/encoder.cindex 8b14b41..51617d0 100644--- a/encoder/encoder.c+++ b/encoder/encoder.c@@ -742,7 +742,7 @@ static int x264_validate_parameters( x264_t *h )      {         const x264_level_t *l = x264_levels;-        if( h->param.i_level_idc < 0 )+        if( h->param.i_level_idc == X264_LEVEL_IDC_AUTO )         {             int maxrate_bak = h->param.rc.i_vbv_max_bitrate;             if( h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.i_vbv_buffer_size <= 0 )diff --git a/encoder/set.c b/encoder/set.cindex 6cf0c6a..0a8a110 100644--- a/encoder/set.c+++ b/encoder/set.c@@ -115,6 +115,18 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )     else         sps->i_profile_idc  = PROFILE_BASELINE; +    /* Hack: if the user specifies a High-compatible VBV, but not a Main-compatible one,+     * switch to High profile.  Prevents spurious errors on the first pass. */+    const x264_level_t *l = x264_get_level( param->i_level_idc );+    if( l && sps->i_profile_idc <= PROFILE_MAIN &&+        l->bitrate * 5/4 >= param->rc.i_vbv_max_bitrate &&+        l->cpb     * 5/4 >= param->rc.i_vbv_buffer_size &&+        (l->bitrate < param->rc.i_vbv_max_bitrate || l->cpb < param->rc.i_vbv_buffer_size) )+    {+        sps->i_profile_idc  = PROFILE_HIGH;+    }+        +     sps->b_constraint_set0  = sps->i_profile_idc == PROFILE_BASELINE;     /* x264 doesn't support the features that are in Baseline and not in Main,      * namely arbitrary_slice_order and slice_groups. */@@ -670,6 +682,16 @@ const x264_level_t x264_levels[] =     { 0 } }; +const x264_level_t *x264_get_level( int level_idc )+{+    const x264_level_t *l = x264_levels;+    while( l->level_idc != 0 && l->level_idc != level_idc )+        l++;+    if( l->level_idc )+        return l;+    return NULL;+}+ #define ERROR(...)\ {\     if( verbose )\@@ -681,7 +703,8 @@ int x264_validate_levels( x264_t *h, int verbose ) {     int ret = 0;     int mbs = h->sps->i_mb_width * h->sps->i_mb_height;-    int dpb = mbs * 384 * h->sps->vui.i_max_dec_frame_buffering;+    int mb_size = 384*BIT_DEPTH/8;+    int dpb = mbs * mb_size * h->sps->vui.i_max_dec_frame_buffering;     int cbp_factor = h->sps->i_profile_idc==PROFILE_HIGH10 ? 12 :                      h->sps->i_profile_idc==PROFILE_HIGH ? 5 : 4; @@ -696,7 +719,7 @@ int x264_validate_levels( x264_t *h, int verbose )                h->sps->i_mb_width, h->sps->i_mb_height, l->frame_size );     if( dpb > l->dpb )         ERROR( "DPB size (%d frames, %d bytes) > level limit (%d frames, %d bytes)\n",-                h->sps->vui.i_max_dec_frame_buffering, dpb, (int)(l->dpb / (384*mbs)), l->dpb );+                h->sps->vui.i_max_dec_frame_buffering, dpb, (int)(l->dpb / (mb_size*mbs)), l->dpb );  #define CHECK( name, limit, val ) \     if( (val) > (limit) ) \diff --git a/encoder/set.h b/encoder/set.hindex 6d70e96..d034a69 100644--- a/encoder/set.h+++ b/encoder/set.h@@ -33,6 +33,7 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t * void x264_pps_write( bs_t *s, x264_pps_t *pps ); void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt ); int  x264_sei_version_write( x264_t *h, bs_t *s );+const x264_level_t *x264_get_level( int level_idc ); int  x264_validate_levels( x264_t *h, int verbose ); void x264_sei_buffering_period_write( x264_t *h, bs_t *s ); void x264_sei_pic_timing_write( x264_t *h, bs_t *s );diff --git a/x264.c b/x264.cindex bba17b8..5cc72d1 100644--- a/x264.c+++ b/x264.c@@ -770,7 +770,8 @@ enum     OPT_INPUT_RES,     OPT_INPUT_CSP,     OPT_INPUT_DEPTH,-    OPT_DTS_COMPRESSION+    OPT_DTS_COMPRESSION,+    OPT_DEVICE } OptionsOPT;  static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw";@@ -781,6 +782,7 @@ static struct option long_options[] =     { "fullhelp",          no_argument, NULL, OPT_FULLHELP },     { "version",           no_argument, NULL, 'V' },     { "profile",     required_argument, NULL, OPT_PROFILE },+    { "device",      required_argument, NULL, OPT_DEVICE },     { "preset",      required_argument, NULL, OPT_PRESET },     { "tune",        required_argument, NULL, OPT_TUNE },     { "slow-firstpass",    no_argument, NULL, OPT_SLOWFIRSTPASS },@@ -928,6 +930,140 @@ static struct option long_options[] =     {0, 0, 0, 0} }; +const x264_device_t x264_device_psp = {480, 272, 8, "main"};+const x264_device_t x264_device_ipod = {320, 240, 8, "baseline"};+const x264_device_t x264_device_ps3 = {1920, 1080, 12, "high"};+const x264_device_t x264_device_iphone = {480, 320, 8, "baseline"};+const x264_device_t x264_device_iphone4 = {960, 640, 8, "main"};+const x264_device_t x264_device_xbox360 = {1920, 1080, 12, "high"};+const x264_device_t x264_device_ipad = {1024, 768, 9, "main"};+const x264_device_t x264_device_wdtv = {1920, 1080, 12, "high"};++const x264_device_t *x264_get_device( const char *device )+{+    if( !strcasecmp( device, "psp" ) ) return &x264_device_psp;+    else if( !strcasecmp( device, "ipod" ) ) return &x264_device_ipod;+    else if( !strcasecmp( device, "ps3" ) ) return &x264_device_ps3;+    else if( !strcasecmp( device, "iphone" ) ) return &x264_device_iphone;+    else if( !strcasecmp( device, "iphone4" ) ) return &x264_device_iphone4;+    else if( !strcasecmp( device, "xbox360" ) ) return &x264_device_xbox360;+    else if( !strcasecmp( device, "ipad" ) ) return &x264_device_ipad;+    else if( !strcasecmp( device, "wdtv" ) ) return &x264_device_wdtv;+    else+    {+        x264_log( NULL, X264_LOG_ERROR, "invalid device: %s\n", device );+        return NULL;+    }+}++const int x264_get_profile( const char *p_profile )+{+    if( !strcmp( p_profile, "baseline" ) ) return PROFILE_BASELINE;+    else if( !strcmp( p_profile, "main" ) ) return PROFILE_MAIN;+    else if( !strcmp( p_profile, "high" ) ) return PROFILE_HIGH;+    else if( !strcmp( p_profile, "high10" ) ) return PROFILE_HIGH10;+    else x264_log( NULL, X264_LOG_ERROR, "invalid profile: %s\n", p_profile );+    return 0;+}++int x264_param_apply_device_restrictions( x264_param_t *param, const char *device )+{+    x264_param_t orig;+    memcpy( &orig, param, sizeof( x264_param_t ) );+    if( !strcmp( device, "psp" ) )+    {+        if( param->i_frame_reference > 3 )+        {+            param->i_frame_reference = 3;+            x264_log( NULL, X264_LOG_WARNING, "Reference frames set to 3\n" );+        }+        if ( param->i_bframe_pyramid > 0 )+        {+            param->i_bframe_pyramid = 0;+            x264_log( NULL, X264_LOG_WARNING, "B-Pyramids disabled\n" );+        }+            +    }+    if( !memcmp( &orig, param, sizeof( x264_param_t ) ) ) return 0;+    return 1;+}++x264_param_t *x264_param_apply_device( x264_param_t *param, const char *device )+{   +    const x264_device_t *_device;+    int height = param->i_height;+    int width = param->i_width;+    if( !( _device = x264_get_device( device ) ) ) return NULL;+    if( _device->i_level_idc < param->i_level_idc )+    {+        x264_level_t level = x264_levels[ _device->i_level_idc ];+        double ratio = ( double )param->i_width / ( double )param->i_height;+        double max_area = level.frame_size * 256;+        width = sqrt( max_area * ratio );+        height = width / ratio;+    }+    if ( width % 2 ) width--;+    if ( height % 2 ) height--;+    param->i_width = width;+    param->i_height = height;+    param->i_level_idc = x264_levels[ _device->i_level_idc ].level_idc;+    for( int i = 0;; i++ )+    {+        if( _device->confstring[i][0] == 0 ) break;+        x264_param_parse( param, _device->confstring[i][0], _device->confstring[i][1] );+    }+    x264_param_apply_profile( param, _device->p_profile );+    x264_param_apply_level( param, _device->p_profile );+    x264_param_apply_device_restrictions( param, device );+    return param;+}++int x264_parse_device( x264_param_t *param, const char *device )+{+    if( !device ) return -1;+    char *tmp = x264_malloc( strlen( device ) + 1 );+    tmp = strcpy( tmp, device );+    char *s = strtok( tmp, ",./-+" );+    while( s )+    {+        if( !strcasecmp( s, "psp" ) )+        {+            if( !x264_param_apply_device( param, "psp" ) ) return -1;+        }+        else if( !strcasecmp( s, "ipod" ) )+        {+            if( !x264_param_apply_device( param, "ipod" ) ) return -1;+        }+        else if( !strcasecmp( s, "ps3" ) )+        {+            if( !x264_param_apply_device( param, "ps3" ) ) return -1;+        }+        else if( !strcasecmp( s, "iphone" ) )+        {+            if( !x264_param_apply_device( param, "iphone" ) ) return -1;+        }+        else if ( !strcasecmp( s, "iphone4" ) )+        {+            if( !x264_param_apply_device( param, "iphone4" ) ) return -1;+        }+        else if( !strcasecmp( s, "xbox360" ) )+        {+            if( !x264_param_apply_device( param, "xbox360" ) ) return -1;+        }+        else if( !strcasecmp( s, "ipad" ) )+        {+            if( !x264_param_apply_device( param, "ipad" ) ) return -1;;+        }+        else if( !strcasecmp( s, "wdtv" ) )+        {+            if( !x264_param_apply_device( param, "wdtv" ) ) return -1;;+        }+        s = strtok( NULL, ",./-+" );+    }+    x264_free( tmp );+    return 0;+}+ static int select_output( const char *muxer, char *filename, x264_param_t *param ) {     const char *ext = get_filename_extension( filename );@@ -975,6 +1111,7 @@ static int select_input( const char *demuxer, char *used_demuxer, char *filename     int b_regular = strcmp( filename, "-" );     if( !b_regular && b_auto )         ext = "raw";+     b_regular = b_regular && x264_is_regular_file_path( filename );     if( b_regular )     {@@ -1127,6 +1264,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )     char *tcfile_name = NULL;     x264_param_t defaults;     char *profile = NULL;+    char *devices = NULL;     char *vid_filters = NULL;     int b_thread_input = 0;     int b_turbo = 1;@@ -1296,6 +1434,9 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )             case OPT_DTS_COMPRESSION:                 output_opt.use_dts_compress = 1;                 break;+            case OPT_DEVICE:+                devices = optarg;+                break;             default: generic_option:             {@@ -1458,23 +1599,10 @@ generic_option:         param->b_tff = !!info.tff;     } -    /* Automatically reduce reference frame count to match the user's target level-     * if the user didn't explicitly set a reference frame count. */-    if( !b_user_ref )-    {-        int mbs = (((param->i_width)+15)>>4) * (((param->i_height)+15)>>4);-        for( int i = 0; x264_levels[i].level_idc != 0; i++ )-            if( param->i_level_idc == x264_levels[i].level_idc )-            {-                while( mbs * 384 * param->i_frame_reference > x264_levels[i].dpb &&-                       param->i_frame_reference > 1 )-                {-                    param->i_frame_reference--;-                }-                break;-            }-    }-+    if( x264_param_apply_level( param, profile ) < 0 )+        return -1;+    +    x264_parse_device( param, devices );      return 0; }@@ -1653,7 +1781,6 @@ static int encode( x264_param_t *param, cli_opt_t *opt )             break;         x264_picture_init( &pic );         convert_cli_to_lib_pic( &pic, &cli_pic );-         if( !param->b_vfr_input )             pic.i_pts = i_frame; diff --git a/x264.h b/x264.hindex ce79d40..034d077 100644--- a/x264.h+++ b/x264.h@@ -161,6 +161,7 @@ typedef struct #define X264_OPEN_GOP_NONE           0 #define X264_OPEN_GOP_NORMAL         1 #define X264_OPEN_GOP_BLURAY         2+#define X264_LEVEL_IDC_AUTO          (-1)  static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 }; static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", "tesa", 0 };@@ -223,6 +224,15 @@ typedef struct     struct x264_param_t *param; } x264_zone_t; +typedef struct+{+    int     i_screen_width;+    int     i_screen_height;+    int     i_level_idc;+    char   *p_profile;+    char   *confstring[5][3];+} x264_device_t;+ typedef struct x264_param_t {     /* CPU flags */@@ -524,6 +534,7 @@ int x264_param_parse( x264_param_t *, const char *name, const char *value );  * 2) Custom user options (via param_parse or directly assigned variables)  * 3) x264_param_apply_fastfirstpass  * 4) x264_param_apply_profile+ * 5) x264_param_apply_level  *  * Additionally, x264CLI does not apply step 3 if the preset chosen is "placebo"  * or --slow-firstpass is set. */@@ -576,6 +587,51 @@ static const char * const x264_profile_names[] = { "baseline", "main", "high", "  *      returns 0 on success, negative on failure (e.g. invalid profile name). */ int     x264_param_apply_profile( x264_param_t *, const char *profile ); +/* x264_param_apply_level:+ *      Applies the restrictions of the level set in the passed x264_param_t to+ *      the passed x264_param_t, using the passed profile.+ *      Uses the level_idc values from x264_levels[].+ *+ *      Does nothing (but is considered success) if the level is set to+ *      X264_LEVEL_IDC_AUTO (default).+ *+ *      x264_param_apply_level does not check or modify parameters related+ *      to properties of the source video that may violate levels, e.g.+ *      resolution, framerate, interlacing.  x264_param_apply_level is not+ *      intended as a compatibility check; this is done inside x264 at the+ *      start of encoding.+ *+ *      i_width and i_height must be initialized for x264_param_apply_level+ *      to work properly.+ *+ *      returns 0 on success, negative on failure (e.g. invalid level). */+int     x264_param_apply_level( x264_param_t *, const char *profile );++/* x264_get_device:+ *      Gets the x264_device_t that matches the passed device name. Returns a NULL+ *      pointer and logs an error if one does not exist.+*/+const x264_device_t *x264_get_device( const char *device );++/* x264_get_profile:+ *      Returns the #defined PROFILE_* relevant to the profile name in p_profile.+ *      If one does not exist, it returns 0 and logs an error.+*/+const int x264_get_profile( const char *p_profile );++/* x264_param_apply_devices:+ *      Applies the device constraints listed in the passed x264_device_t to the+ *      passed x264_param_t. Returns the passed x264_param_t if successful or a+ *      NULL pointer if the device could not be found.+*/+x264_param_t *x264_param_apply_devices( x264_param_t *param, const char *device );++/* x264_parse_device:+ *      Parses the comma-seperated devices string supplied with the commandline+ *      arguments. Returns 0 if successful.+*/+int x264_parse_device( x264_param_t *param, const char *device );+ /****************************************************************************  * Picture structures and functions  ****************************************************************************/