From: Jan Ekström Date: Sun, 7 Oct 2012 18:12:05 +0000 (+0300) Subject: Add support for the ffmpeg/vapoursynth high bit depth y4m extensions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cc61a4b4d0838b6d5f4cdaf88a0b6d06a12b6d3e;p=libx264 Add support for the ffmpeg/vapoursynth high bit depth y4m extensions --- diff --git a/input/y4m.c b/input/y4m.c index 6f37b0e8..e60b27a6 100644 --- a/input/y4m.c +++ b/input/y4m.c @@ -35,6 +35,7 @@ typedef struct int frame_header_len; uint64_t frame_size; uint64_t plane_size[3]; + int bit_depth; } y4m_hnd_t; #define Y4M_MAGIC "YUV4MPEG2" @@ -42,15 +43,23 @@ typedef struct #define Y4M_FRAME_MAGIC "FRAME" #define MAX_FRAME_HEADER 80 -static int csp_string_to_int( char *csp_name ) +static int parse_csp_and_depth( char *csp_name, int *bit_depth ) { - int csp = X264_CSP_MAX; + int csp = X264_CSP_MAX; + *bit_depth = 8; + + /* Set colorspace from known variants */ if( !strncmp( "420", csp_name, 3 ) ) csp = X264_CSP_I420; else if( !strncmp( "422", csp_name, 3 ) ) csp = X264_CSP_I422; else if( !strncmp( "444", csp_name, 3 ) && strncmp( "444alpha", csp_name, 8 ) ) // only accept alphaless 4:4:4 csp = X264_CSP_I444; + + /* Set high bit depth from known extensions */ + if( !strncmp( "p", csp_name + 3, 1 ) ) + *bit_depth = strtol( csp_name + 4, NULL, 10 ); + return csp; } @@ -63,6 +72,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c char *tokend, *header_end; int colorspace = X264_CSP_NONE; int alt_colorspace = X264_CSP_NONE; + int alt_bit_depth = 8; if( !h ) return -1; @@ -112,7 +122,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c tokstart=tokend; break; case 'C': /* Color space */ - colorspace = csp_string_to_int( tokstart ); + colorspace = parse_csp_and_depth( tokstart, &h->bit_depth ); tokstart = strchr( tokstart, 0x20 ); break; case 'I': /* Interlace type */ @@ -159,7 +169,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c { /* Older nonstandard pixel format representation */ tokstart += 6; - alt_colorspace = csp_string_to_int( tokstart ); + alt_colorspace = parse_csp_and_depth( tokstart, &alt_bit_depth ); } tokstart = strchr( tokstart, 0x20 ); break; @@ -167,22 +177,37 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c } if( colorspace == X264_CSP_NONE ) - colorspace = alt_colorspace; + { + colorspace = alt_colorspace; + h->bit_depth = alt_bit_depth; + } - // default to 4:2:0 if nothing is specified + // default to 8bit 4:2:0 if nothing is specified if( colorspace == X264_CSP_NONE ) - colorspace = X264_CSP_I420; + { + colorspace = X264_CSP_I420; + h->bit_depth = 8; + } FAIL_IF_ERROR( colorspace <= X264_CSP_NONE || colorspace >= X264_CSP_MAX, "colorspace unhandled\n" ) + FAIL_IF_ERROR( h->bit_depth < 8 || h->bit_depth > 16, "unsupported bit depth `%d'\n", h->bit_depth ); info->thread_safe = 1; info->num_frames = 0; info->csp = colorspace; h->frame_size = h->frame_header_len; - for( i = 0; i < x264_cli_csps[info->csp].planes; i++ ) + + if( h->bit_depth > 8 ) + info->csp |= X264_CSP_HIGH_DEPTH; + + const x264_cli_csp_t *csp = x264_cli_get_csp( info->csp ); + + for( i = 0; i < csp->planes; i++ ) { h->plane_size[i] = x264_cli_pic_plane_size( info->csp, info->width, info->height, i ); h->frame_size += h->plane_size[i]; + /* x264_cli_pic_plane_size returns the size in bytes, we need the value in pixels from here on */ + h->plane_size[i] /= x264_cli_csp_depth_factor( info->csp ); } /* Most common case: frame_header = "FRAME" */ @@ -202,6 +227,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h ) { size_t slen = strlen( Y4M_FRAME_MAGIC ); + int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); int i = 0; char header[16]; @@ -222,7 +248,19 @@ static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h ) int error = 0; for( i = 0; i < pic->img.planes && !error; i++ ) - error |= fread( pic->img.plane[i], h->plane_size[i], 1, h->fh ) <= 0; + { + error |= fread( pic->img.plane[i], pixel_depth, h->plane_size[i], h->fh ) != h->plane_size[i]; + if( h->bit_depth & 7 ) + { + /* upconvert non 16bit high depth planes to 16bit using the same + * algorithm as used in the depth filter. */ + uint16_t *plane = (uint16_t*)pic->img.plane[i]; + uint64_t pixel_count = h->plane_size[i]; + int lshift = 16 - h->bit_depth; + for( uint64_t j = 0; j < pixel_count; j++ ) + plane[j] = plane[j] << lshift; + } + } return error; }