From ce55ae08a6aad516e6aa2ed58fd93a2adf39a997 Mon Sep 17 00:00:00 2001 From: xvidfan Date: Wed, 22 Jun 2011 18:46:14 -0700 Subject: [PATCH] RGB encoding support Much less efficient than YUV444, but easy to support using the YUV444 framework. --- common/common.c | 4 +-- common/frame.c | 67 +++++++++++++++++++++++++++++++---------------- common/mc.c | 17 ++++++++++++ common/mc.h | 5 +++- encoder/encoder.c | 4 +-- encoder/set.c | 6 +++-- input/avs.c | 24 +++++++---------- input/input.h | 5 +--- x264.c | 6 +++-- x264.h | 5 +++- 10 files changed, 91 insertions(+), 52 deletions(-) diff --git a/common/common.c b/common/common.c index 99cb3d2f..5a5e036b 100644 --- a/common/common.c +++ b/common/common.c @@ -59,10 +59,10 @@ void x264_param_default( x264_param_t *param ) param->vui.i_sar_height= 0; param->vui.i_overscan = 0; /* undef */ param->vui.i_vidformat = 5; /* undef */ - param->vui.b_fullrange = 0; /* off */ + param->vui.b_fullrange = -1; /* default depends on input */ param->vui.i_colorprim = 2; /* undef */ param->vui.i_transfer = 2; /* undef */ - param->vui.i_colmatrix = 2; /* undef */ + param->vui.i_colmatrix = -1; /* default depends on input */ param->vui.i_chroma_loc= 0; /* left center */ param->i_fps_num = 25; param->i_fps_den = 1; diff --git a/common/frame.c b/common/frame.c index daf446e2..09f20790 100644 --- a/common/frame.c +++ b/common/frame.c @@ -52,6 +52,9 @@ static int x264_frame_internal_csp( int external_csp ) return X264_CSP_NV12; case X264_CSP_I444: case X264_CSP_YV24: + case X264_CSP_BGR: + case X264_CSP_BGRA: + case X264_CSP_RGB: return X264_CSP_I444; default: return X264_CSP_NONE; @@ -346,32 +349,50 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ) uint8_t *pix[3]; int stride[3]; - get_plane_ptr( h, src, &pix[0], &stride[0], 0, 0, 0 ); - h->mc.plane_copy( dst->plane[0], dst->i_stride[0], (pixel*)pix[0], - stride[0]/sizeof(pixel), h->param.i_width, h->param.i_height ); - if( i_csp == X264_CSP_NV12 ) - { - get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, 1 ); - h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], - stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height>>1 ); - } - else if( i_csp == X264_CSP_I420 || i_csp == X264_CSP_YV12 ) + if ( i_csp >= X264_CSP_BGR ) { - get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I420 ? 1 : 2, 1, 1 ); - get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I420 ? 2 : 1, 1, 1 ); - h->mc.plane_copy_interleave( dst->plane[1], dst->i_stride[1], - (pixel*)pix[1], stride[1]/sizeof(pixel), - (pixel*)pix[2], stride[2]/sizeof(pixel), - h->param.i_width>>1, h->param.i_height>>1 ); + stride[0] = src->img.i_stride[0]; + pix[0] = src->img.plane[0]; + if( src->img.i_csp & X264_CSP_VFLIP ) + { + pix[0] += (h->param.i_height-1) * stride[0]; + stride[0] = -stride[0]; + } + int b = i_csp==X264_CSP_RGB ? 2 : 0; + h->mc.plane_copy_deinterleave_rgb( dst->plane[1], dst->i_stride[1], + dst->plane[b], dst->i_stride[b], + dst->plane[2-b], dst->i_stride[2-b], + (pixel*)pix[0], stride[0]/sizeof(pixel), i_csp==X264_CSP_BGRA ? 4 : 3, h->param.i_width, h->param.i_height ); } - else //if( i_csp == X264_CSP_I444 || i_csp == X264_CSP_YV24 ) + else { - get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I444 ? 1 : 2, 0, 0 ); - get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I444 ? 2 : 1, 0, 0 ); - h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], - stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height ); - h->mc.plane_copy( dst->plane[2], dst->i_stride[2], (pixel*)pix[2], - stride[2]/sizeof(pixel), h->param.i_width, h->param.i_height ); + get_plane_ptr( h, src, &pix[0], &stride[0], 0, 0, 0 ); + h->mc.plane_copy( dst->plane[0], dst->i_stride[0], (pixel*)pix[0], + stride[0]/sizeof(pixel), h->param.i_width, h->param.i_height ); + if( i_csp == X264_CSP_NV12 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], 1, 0, 1 ); + h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], + stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height>>1 ); + } + else if( i_csp == X264_CSP_I420 || i_csp == X264_CSP_YV12 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I420 ? 1 : 2, 1, 1 ); + get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I420 ? 2 : 1, 1, 1 ); + h->mc.plane_copy_interleave( dst->plane[1], dst->i_stride[1], + (pixel*)pix[1], stride[1]/sizeof(pixel), + (pixel*)pix[2], stride[2]/sizeof(pixel), + h->param.i_width>>1, h->param.i_height>>1 ); + } + else //if( i_csp == X264_CSP_I444 || i_csp == X264_CSP_YV24 ) + { + get_plane_ptr( h, src, &pix[1], &stride[1], i_csp==X264_CSP_I444 ? 1 : 2, 0, 0 ); + get_plane_ptr( h, src, &pix[2], &stride[2], i_csp==X264_CSP_I444 ? 2 : 1, 0, 0 ); + h->mc.plane_copy( dst->plane[1], dst->i_stride[1], (pixel*)pix[1], + stride[1]/sizeof(pixel), h->param.i_width, h->param.i_height ); + h->mc.plane_copy( dst->plane[2], dst->i_stride[2], (pixel*)pix[2], + stride[2]/sizeof(pixel), h->param.i_width, h->param.i_height ); + } } return 0; } diff --git a/common/mc.c b/common/mc.c index 8c4c2b9e..de1c6784 100644 --- a/common/mc.c +++ b/common/mc.c @@ -314,6 +314,22 @@ void x264_plane_copy_deinterleave_c( pixel *dstu, int i_dstu, } } +void x264_plane_copy_deinterleave_rgb_c( pixel *dsta, int i_dsta, + pixel *dstb, int i_dstb, + pixel *dstc, int i_dstc, + pixel *src, int i_src, int pw, int w, int h ) +{ + for( int y=0; yplane_copy = x264_plane_copy_c; pf->plane_copy_interleave = x264_plane_copy_interleave_c; pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_c; + pf->plane_copy_deinterleave_rgb = x264_plane_copy_deinterleave_rgb_c; pf->hpel_filter = hpel_filter; diff --git a/common/mc.h b/common/mc.h index 4882707d..f19a9979 100644 --- a/common/mc.h +++ b/common/mc.h @@ -96,7 +96,10 @@ typedef struct void (*plane_copy_deinterleave)( pixel *dstu, int i_dstu, pixel *dstv, int i_dstv, pixel *src, int i_src, int w, int h ); - + void (*plane_copy_deinterleave_rgb)( pixel *dsta, int i_dsta, + pixel *dstb, int i_dstb, + pixel *dstc, int i_dstc, + pixel *src, int i_src, int pw, int w, int h ); void (*hpel_filter)( pixel *dsth, pixel *dstv, pixel *dstc, pixel *src, int i_stride, int i_width, int i_height, int16_t *buf ); diff --git a/encoder/encoder.c b/encoder/encoder.c index b988b9a6..a6a3415c 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -410,7 +410,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) int i_csp = h->param.i_csp & X264_CSP_MASK; if( i_csp <= X264_CSP_NONE || i_csp >= X264_CSP_MAX ) { - x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420/YV12/NV12/I444/YV24 supported)\n" ); + x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420/YV12/NV12/I444/YV24/BGR/BGRA/RGB supported)\n" ); return -1; } @@ -767,7 +767,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->mb.i_psy_rd = h->param.analyse.i_subpel_refine >= 6 ? FIX8( h->param.analyse.f_psy_rd ) : 0; h->mb.i_psy_trellis = h->param.analyse.i_trellis ? FIX8( h->param.analyse.f_psy_trellis / 4 ) : 0; /* In 4:4:4 mode, chroma gets twice as much resolution, so we can halve its quality. */ - if( b_open && i_csp >= X264_CSP_I444 && h->param.analyse.b_psy ) + if( b_open && i_csp >= X264_CSP_I444 && i_csp < X264_CSP_BGR && h->param.analyse.b_psy ) h->param.analyse.i_chroma_qp_offset += 6; /* Psy RDO increases overall quantizers to improve the quality of luma--this indirectly hurts chroma quality */ /* so we lower the chroma QP offset to compensate */ diff --git a/encoder/set.c b/encoder/set.c index 0044e584..c5190129 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -202,12 +202,14 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) sps->vui.b_signal_type_present = 0; sps->vui.i_vidformat = ( param->vui.i_vidformat >= 0 && param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 ); - sps->vui.b_fullrange = ( param->vui.b_fullrange ? 1 : 0 ); + sps->vui.b_fullrange = ( param->vui.b_fullrange >= 0 && param->vui.b_fullrange <= 1 ? param->vui.b_fullrange : + ( param->i_csp >= X264_CSP_BGR ? 1 : 0 ) ); sps->vui.b_color_description_present = 0; sps->vui.i_colorprim = ( param->vui.i_colorprim >= 0 && param->vui.i_colorprim <= 8 ? param->vui.i_colorprim : 2 ); sps->vui.i_transfer = ( param->vui.i_transfer >= 0 && param->vui.i_transfer <= 10 ? param->vui.i_transfer : 2 ); - sps->vui.i_colmatrix = ( param->vui.i_colmatrix >= 0 && param->vui.i_colmatrix <= 8 ? param->vui.i_colmatrix : 2 ); + sps->vui.i_colmatrix = ( param->vui.i_colmatrix >= 0 && param->vui.i_colmatrix <= 8 ? param->vui.i_colmatrix : + ( param->i_csp >= X264_CSP_BGR ? 0 : 2 ) ); if( sps->vui.i_colorprim != 2 || sps->vui.i_transfer != 2 || sps->vui.i_colmatrix != 2 ) diff --git a/input/avs.c b/input/avs.c index f3f1118d..59fab8cc 100644 --- a/input/avs.c +++ b/input/avs.c @@ -219,11 +219,12 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c } #if !HAVE_SWSCALE /* if swscale is not available, convert the CSP if necessary */ - if( (opt->output_csp == X264_CSP_I420 && !avs_is_yv12( vi )) || (opt->output_csp == X264_CSP_I444 && !avs_is_yv24( vi )) ) + if( (opt->output_csp == X264_CSP_I420 && !avs_is_yv12( vi )) || (opt->output_csp == X264_CSP_I444 && !avs_is_yv24( vi )) || + (opt->output_csp == X264_CSP_RGB && !avs_is_rgb( vi )) ) { FAIL_IF_ERROR( avs_version < 2.6f && opt->output_csp == X264_CSP_I444, "avisynth >= 2.6 is required for i444 output\n" ) - const char *csp = opt->output_csp == X264_CSP_I420 ? "YV12" : "YV24"; + const char *csp = opt->output_csp == X264_CSP_I420 ? "YV12" : (opt->output_csp == X264_CSP_I444 ? "YV24" : "RGB"); x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to %s\n", csp ); FAIL_IF_ERROR( opt->output_csp == X264_CSP_I420 && (vi->width&1 || vi->height&1), "input clip width or height not divisible by 2 (%dx%d)\n", vi->width, vi->height ) @@ -244,33 +245,26 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c info->fps_den = vi->fps_denominator; h->num_frames = info->num_frames = vi->num_frames; info->thread_safe = 1; -#if HAVE_SWSCALE if( avs_is_rgb32( vi ) ) info->csp = X264_CSP_BGRA | X264_CSP_VFLIP; else if( avs_is_rgb24( vi ) ) info->csp = X264_CSP_BGR | X264_CSP_VFLIP; - else if( avs_is_yuy2( vi ) ) - info->csp = PIX_FMT_YUYV422 | X264_CSP_OTHER; else if( avs_is_yv24( vi ) ) info->csp = X264_CSP_I444; + else if( avs_is_yv12( vi ) ) + info->csp = X264_CSP_I420; +#if HAVE_SWSCALE + else if( avs_is_yuy2( vi ) ) + info->csp = PIX_FMT_YUYV422 | X264_CSP_OTHER; else if( avs_is_yv16( vi ) ) info->csp = X264_CSP_I422; - else if( avs_is_yv12( vi ) ) - info->csp = X264_CSP_I420; else if( avs_is_yv411( vi ) ) info->csp = PIX_FMT_YUV411P | X264_CSP_OTHER; else if( avs_is_y8( vi ) ) info->csp = PIX_FMT_GRAY8 | X264_CSP_OTHER; +#endif else info->csp = X264_CSP_NONE; -#else - if( avs_is_yv24( vi ) ) - info->csp = X264_CSP_I444; - else if( avs_is_yv12( vi ) ) - info->csp = X264_CSP_I420; - else - info->csp = X264_CSP_NONE; -#endif info->vfr = 0; *p_handle = h; diff --git a/input/input.h b/input/input.h index 488833d0..eb928eac 100644 --- a/input/input.h +++ b/input/input.h @@ -104,10 +104,7 @@ extern cli_input_t input; /* extended colorspace list that isn't supported by libx264 but by the cli */ #define X264_CSP_I422 X264_CSP_MAX /* yuv 4:2:2 planar */ -#define X264_CSP_BGR (X264_CSP_MAX+1) /* packed bgr 24bits */ -#define X264_CSP_BGRA (X264_CSP_MAX+2) /* packed bgr 32bits */ -#define X264_CSP_RGB (X264_CSP_MAX+3) /* packed rgb 24bits */ -#define X264_CSP_CLI_MAX (X264_CSP_MAX+4) /* end of list */ +#define X264_CSP_CLI_MAX (X264_CSP_MAX+1) /* end of list */ #define X264_CSP_OTHER 0x4000 /* non x264 colorspace */ typedef struct diff --git a/x264.c b/x264.c index ea7c5cdf..3b58aa7d 100644 --- a/x264.c +++ b/x264.c @@ -121,7 +121,7 @@ static const char * const muxer_names[] = static const char * const pulldown_names[] = { "none", "22", "32", "64", "double", "triple", "euro", 0 }; static const char * const log_level_names[] = { "none", "error", "warning", "info", "debug", 0 }; -static const char * const output_csp_names[] = { "i420", "i444", 0 }; +static const char * const output_csp_names[] = { "i420", "i444", "rgb", 0 }; typedef struct { @@ -1129,6 +1129,8 @@ static int init_vid_filters( char *sequence, hnd_t *handle, video_info_t *info, param->i_csp = X264_CSP_I420; else if( output_csp == X264_CSP_I444 && (csp < X264_CSP_I444 || csp > X264_CSP_YV24) ) param->i_csp = X264_CSP_I444; + else if( output_csp == X264_CSP_RGB && (csp < X264_CSP_BGR || csp > X264_CSP_RGB) ) + param->i_csp = X264_CSP_RGB; param->i_csp |= info->csp & X264_CSP_HIGH_DEPTH; if( x264_init_vid_filter( "resize", handle, &filter, info, param, NULL ) ) @@ -1349,7 +1351,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) case OPT_OUTPUT_CSP: FAIL_IF_ERROR( parse_enum_value( optarg, output_csp_names, &output_csp ), "Unknown output csp `%s'\n", optarg ) // correct the parsed value to the libx264 csp value - output_csp = !output_csp ? X264_CSP_I420 : X264_CSP_I444; + output_csp = !output_csp ? X264_CSP_I420 : (output_csp == 1 ? X264_CSP_I444 : X264_CSP_RGB); break; default: generic_option: diff --git a/x264.h b/x264.h index f936443d..809cefd7 100644 --- a/x264.h +++ b/x264.h @@ -182,7 +182,10 @@ static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; #define X264_CSP_NV12 0x0003 /* yuv 4:2:0, with one y plane and one packed u+v */ #define X264_CSP_I444 0x0004 /* yuv 4:4:4 planar */ #define X264_CSP_YV24 0x0005 /* yvu 4:4:4 planar */ -#define X264_CSP_MAX 0x0006 /* end of list */ +#define X264_CSP_BGR 0x0006 /* packed bgr 24bits */ +#define X264_CSP_BGRA 0x0007 /* packed bgr 32bits */ +#define X264_CSP_RGB 0x0008 /* packed rgb 24bits */ +#define X264_CSP_MAX 0x0009 /* end of list */ #define X264_CSP_VFLIP 0x1000 /* the csp is vertically flipped */ #define X264_CSP_HIGH_DEPTH 0x2000 /* the csp has a depth of 16 bits per pixel component */ -- 2.39.2