static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string ) { int ret = 0; int change_fmt = (info->csp ^ param->i_csp) & X264_CSP_HIGH_DEPTH; int csp = ~(~info->csp ^ change_fmt); int bit_depth = 8*x264_cli_csp_depth_factor( csp ); if( opt_string ) { static const char * const optlist[] = { "bit_depth", NULL }; char **opts = x264_split_options( opt_string, optlist ); if( opts ) { char *str_bit_depth = x264_get_option( "bit_depth", opts ); bit_depth = x264_otoi( str_bit_depth, -1 ); ret = bit_depth < 8 || bit_depth > 16; csp = bit_depth > 8 ? csp | X264_CSP_HIGH_DEPTH : csp & ~X264_CSP_HIGH_DEPTH; change_fmt = (info->csp ^ csp) & X264_CSP_HIGH_DEPTH; free( opts ); } else ret = 1; } FAIL_IF_ERROR( bit_depth != BIT_DEPTH, "this filter supports only bit depth %d\n", BIT_DEPTH ); FAIL_IF_ERROR( ret, "unsupported bit depth conversion.\n" ); /* only add the filter to the chain if it's needed */ if( change_fmt || bit_depth != 8 * x264_cli_csp_depth_factor( csp ) ) { FAIL_IF_ERROR( !depth_filter_csp_is_supported(csp), "unsupported colorspace.\n" ); depth_hnd_t *h = x264_malloc( sizeof(depth_hnd_t) + (info->width+1)*sizeof(int16_t) ); if( !h ) return -1; h->error_buf = (int16_t*)(h + 1); h->dst_csp = csp; h->bit_depth = bit_depth; h->prev_hnd = *handle; h->prev_filter = *filter; if( x264_cli_pic_alloc( &h->buffer, h->dst_csp, info->width, info->height ) ) { x264_free( h ); return -1; } *handle = h; *filter = depth_filter; info->csp = h->dst_csp; } return 0; }
static int read_frame_internal( cli_pic_t *pic, raw_hnd_t *h, int bit_depth_uc ) { int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); for( int i = 0; i < pic->img.planes; i++ ) { if( h->use_mmap ) { if( i ) pic->img.plane[i] = pic->img.plane[i-1] + pixel_depth * h->plane_size[i-1]; } else if( fread( pic->img.plane[i], pixel_depth, h->plane_size[i], h->fh ) != h->plane_size[i] ) return -1; if( bit_depth_uc ) { /* 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 0; }
static int x264_cli_pic_alloc_internal( cli_pic_t *pic, int csp, int width, int height, int align ) { memset( pic, 0, sizeof(cli_pic_t) ); int csp_mask = csp & X264_CSP_MASK; if( x264_cli_csp_is_invalid( csp ) ) pic->img.planes = 0; else pic->img.planes = x264_cli_csps[csp_mask].planes; pic->img.csp = csp; pic->img.width = width; pic->img.height = height; for( int i = 0; i < pic->img.planes; i++ ) { int stride = width * x264_cli_csps[csp_mask].width[i]; stride *= x264_cli_csp_depth_factor( csp ); stride = ALIGN( stride, align ); uint64_t size = (uint64_t)(height * x264_cli_csps[csp_mask].height[i]) * stride; pic->img.plane[i] = x264_malloc( size ); if( !pic->img.plane[i] ) return -1; pic->img.stride[i] = stride; } return 0; }
uint64_t x264_cli_pic_plane_size( int csp, int width, int height, int plane ) { int csp_mask = csp & X264_CSP_MASK; if( x264_cli_csp_is_invalid( csp ) || plane < 0 || plane >= x264_cli_csps[csp_mask].planes ) return 0; uint64_t size = (uint64_t)width * height; size *= x264_cli_csps[csp_mask].width[plane] * x264_cli_csps[csp_mask].height[plane]; size *= x264_cli_csp_depth_factor( csp ); return size; }
static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h, int bit_depth_uc ) { size_t slen = strlen( Y4M_FRAME_MAGIC ); int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); int i = 0; char header[16]; int error = 0; /* Read frame header - without terminating '\n' */ if( fread( header, 1, slen, h->fh ) != slen ) return -1; header[slen] = 0; #if !defined(IDE_COMPILE) || (defined(IDE_COMPILE) && (_MSC_VER >= 1400)) FAIL_IF_ERROR( strncmp( header, Y4M_FRAME_MAGIC, slen ), "bad header magic (%"PRIx32" <=> %s)\n", M32(header), header ) #else if( strncmp( header, Y4M_FRAME_MAGIC, slen ) ){ x264_cli_log( "y4m", 0, "bad header magic (%"PRIx32" <=> %s)\n", M32(header), header ); return -1; } #endif /* Skip most of it */ while( i < MAX_FRAME_HEADER && fgetc( h->fh ) != '\n' ) i++; #if !defined(IDE_COMPILE) || (defined(IDE_COMPILE) && (_MSC_VER >= 1400)) FAIL_IF_ERROR( i == MAX_FRAME_HEADER, "bad frame header!\n" ) #else if( i == MAX_FRAME_HEADER ){ x264_cli_log( "y4m", 0, "bad frame header!\n" ); return -1; } #endif h->frame_size = h->frame_size - h->frame_header_len + i+slen+1; h->frame_header_len = i+slen+1; for( i = 0; i < pic->img.planes && !error; i++ ) { error |= fread( pic->img.plane[i], pixel_depth, h->plane_size[i], h->fh ) != h->plane_size[i]; if( bit_depth_uc ) { /* 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; uint64_t j; for( j = 0; j < pixel_count; j++ ) plane[j] = plane[j] << lshift; } } return error; }
static int handle_opts( const char **optlist, char **opts, video_info_t *info, resizer_hnd_t *h ) { uint32_t out_sar_w, out_sar_h; char *str_width = x264_get_option( optlist[0], opts ); char *str_height = x264_get_option( optlist[1], opts ); char *str_sar = x264_get_option( optlist[2], opts ); char *fittobox = x264_get_option( optlist[3], opts ); char *str_csp = x264_get_option( optlist[4], opts ); int width = x264_otoi( str_width, -1 ); int height = x264_otoi( str_height, -1 ); int csp_only = 0; uint32_t in_sar_w = info->sar_width; uint32_t in_sar_h = info->sar_height; if( str_csp ) { /* output csp was specified, first check if optional depth was provided */ char *str_depth = strchr( str_csp, ':' ); int depth = x264_cli_csp_depth_factor( info->csp ) * 8; if( str_depth ) { /* csp bit depth was specified */ *str_depth++ = '\0'; depth = x264_otoi( str_depth, -1 ); FAIL_IF_ERROR( depth != 8 && depth != 16, "unsupported bit depth %d\n", depth ); } /* now lookup against the list of valid csps */ int csp; if( strlen( str_csp ) == 0 ) csp = info->csp & X264_CSP_MASK; else for( csp = X264_CSP_CLI_MAX-1; csp > X264_CSP_NONE; csp-- ) { if( x264_cli_csps[csp].name && !strcasecmp( x264_cli_csps[csp].name, str_csp ) ) break; } FAIL_IF_ERROR( csp == X264_CSP_NONE, "unsupported colorspace `%s'\n", str_csp ); h->dst_csp = csp; if( depth == 16 ) h->dst_csp |= X264_CSP_HIGH_DEPTH; } /* if the input sar is currently invalid, set it to 1:1 so it can be used in math */ if( !in_sar_w || !in_sar_h ) in_sar_w = in_sar_h = 1; if( str_sar ) { FAIL_IF_ERROR( 2 != sscanf( str_sar, "%u:%u", &out_sar_w, &out_sar_h ) && 2 != sscanf( str_sar, "%u/%u", &out_sar_w, &out_sar_h ), "invalid sar `%s'\n", str_sar ) } else
static int get_frame( hnd_t handle, cli_pic_t *output, int frame ) { crop_hnd_t *h = handle; if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) ) return -1; output->img.width = h->dims[2]; output->img.height = h->dims[3]; /* shift the plane pointers down 'top' rows and right 'left' columns. */ for( int i = 0; i < output->img.planes; i++ ) { intptr_t offset = output->img.stride[i] * h->dims[1] * h->csp->height[i]; offset += h->dims[0] * h->csp->width[i] * x264_cli_csp_depth_factor( output->img.csp ); output->img.plane[i] += offset; } return 0; }
static int read_frame_internal( cli_pic_t *pic, raw_hnd_t *h ) { int error = 0; int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); for( int i = 0; i < pic->img.planes && !error; i++ ) { 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; }
int x264_cli_pic_copy( cli_pic_t *out, cli_pic_t *in ) { int csp = in->img.csp & X264_CSP_MASK; FAIL_IF_ERROR( x264_cli_csp_is_invalid( in->img.csp ), "invalid colorspace arg %d\n", in->img.csp ) FAIL_IF_ERROR( in->img.csp != out->img.csp || in->img.height != out->img.height || in->img.width != out->img.width, "incompatible frame properties\n" ); /* copy data */ out->duration = in->duration; out->pts = in->pts; out->opaque = in->opaque; for( int i = 0; i < out->img.planes; i++ ) { int height = in->img.height * x264_cli_csps[csp].height[i]; int width = in->img.width * x264_cli_csps[csp].width[i]; width *= x264_cli_csp_depth_factor( in->img.csp ); x264_cli_plane_copy( out->img.plane[i], out->img.stride[i], in->img.plane[i], in->img.stride[i], width, height ); } return 0; }
int x264_cli_pic_alloc( cli_pic_t *pic, int csp, int width, int height ) { memset( pic, 0, sizeof(cli_pic_t) ); int csp_mask = csp & X264_CSP_MASK; if( x264_cli_csp_is_invalid( csp ) ) pic->img.planes = 0; else pic->img.planes = x264_cli_csps[csp_mask].planes; pic->img.csp = csp; pic->img.width = width; pic->img.height = height; for( int i = 0; i < pic->img.planes; i++ ) { pic->img.plane[i] = x264_malloc( x264_cli_pic_plane_size( csp, width, height, i ) ); if( !pic->img.plane[i] ) return -1; pic->img.stride[i] = width * x264_cli_csps[csp_mask].width[i] * x264_cli_csp_depth_factor( csp ); } return 0; }
static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) { raw_hnd_t *h = calloc( 1, sizeof(raw_hnd_t) ); if( !h ) return -1; if( !opt->resolution ) { /* try to parse the file name */ for( char *p = psz_filename; *p; p++ ) if( *p >= '0' && *p <= '9' && sscanf( p, "%dx%d", &info->width, &info->height ) == 2 ) break; } else sscanf( opt->resolution, "%dx%d", &info->width, &info->height ); FAIL_IF_ERROR( !info->width || !info->height, "raw input requires a resolution.\n" ) if( opt->colorspace ) { for( info->csp = X264_CSP_CLI_MAX-1; info->csp > X264_CSP_NONE; info->csp-- ) { if( x264_cli_csps[info->csp].name && !strcasecmp( x264_cli_csps[info->csp].name, opt->colorspace ) ) break; } FAIL_IF_ERROR( info->csp == X264_CSP_NONE, "unsupported colorspace `%s'\n", opt->colorspace ); } else /* default */ info->csp = X264_CSP_I420; h->bit_depth = opt->bit_depth; FAIL_IF_ERROR( h->bit_depth < 8 || h->bit_depth > 16, "unsupported bit depth `%d'\n", h->bit_depth ); if( h->bit_depth > 8 ) info->csp |= X264_CSP_HIGH_DEPTH; if( !strcmp( psz_filename, "-" ) ) h->fh = stdin; else h->fh = x264_fopen( psz_filename, "rb" ); if( h->fh == NULL ) return -1; info->thread_safe = 1; info->num_frames = 0; info->vfr = 0; const x264_cli_csp_t *csp = x264_cli_get_csp( info->csp ); for( int 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 ); } if( x264_is_regular_file( h->fh ) ) { fseek( h->fh, 0, SEEK_END ); uint64_t size = ftell( h->fh ); fseek( h->fh, 0, SEEK_SET ); info->num_frames = size / h->frame_size; /* Attempt to use memory-mapped input frames if possible */ if( !(h->bit_depth & 7) ) h->use_mmap = !x264_cli_mmap_init( &h->mmap, h->fh ); } *p_handle = h; return 0; }
static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) { y4m_hnd_t *h = malloc( sizeof(y4m_hnd_t) ); int i; uint32_t n, d; char header[MAX_YUV4_HEADER+10]; char *tokend, *header_end; int colorspace = X264_CSP_NONE; int alt_colorspace = X264_CSP_NONE; int alt_bit_depth = 8; if( !h ) return -1; h->next_frame = 0; info->vfr = 0; if( !strcmp( psz_filename, "-" ) ) h->fh = stdin; else h->fh = fopen(psz_filename, "rb"); if( h->fh == NULL ) return -1; h->frame_header_len = strlen( Y4M_FRAME_MAGIC )+1; /* Read header */ for( i = 0; i < MAX_YUV4_HEADER; i++ ) { header[i] = fgetc( h->fh ); if( header[i] == '\n' ) { /* Add a space after last option. Makes parsing "444" vs "444alpha" easier. */ header[i+1] = 0x20; header[i+2] = 0; break; } } if( i == MAX_YUV4_HEADER || strncmp( header, Y4M_MAGIC, strlen( Y4M_MAGIC ) ) ) return -1; /* Scan properties */ header_end = &header[i+1]; /* Include space */ h->seq_header_len = i+1; for( char *tokstart = &header[strlen( Y4M_MAGIC )+1]; tokstart < header_end; tokstart++ ) { if( *tokstart == 0x20 ) continue; switch( *tokstart++ ) { case 'W': /* Width. Required. */ info->width = strtol( tokstart, &tokend, 10 ); tokstart=tokend; break; case 'H': /* Height. Required. */ info->height = strtol( tokstart, &tokend, 10 ); tokstart=tokend; break; case 'C': /* Color space */ colorspace = parse_csp_and_depth( tokstart, &h->bit_depth ); tokstart = strchr( tokstart, 0x20 ); break; case 'I': /* Interlace type */ switch( *tokstart++ ) { case 't': info->interlaced = 1; info->tff = 1; break; case 'b': info->interlaced = 1; info->tff = 0; break; case 'm': info->interlaced = 1; break; //case '?': //case 'p': default: break; } break; case 'F': /* Frame rate - 0:0 if unknown */ if( sscanf( tokstart, "%u:%u", &n, &d ) == 2 && n && d ) { x264_reduce_fraction( &n, &d ); info->fps_num = n; info->fps_den = d; } tokstart = strchr( tokstart, 0x20 ); break; case 'A': /* Pixel aspect - 0:0 if unknown */ /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */ if( sscanf( tokstart, "%u:%u", &n, &d ) == 2 && n && d ) { x264_reduce_fraction( &n, &d ); info->sar_width = n; info->sar_height = d; } tokstart = strchr( tokstart, 0x20 ); break; case 'X': /* Vendor extensions */ if( !strncmp( "YSCSS=", tokstart, 6 ) ) { /* Older nonstandard pixel format representation */ tokstart += 6; alt_colorspace = parse_csp_and_depth( tokstart, &alt_bit_depth ); } tokstart = strchr( tokstart, 0x20 ); break; } } if( colorspace == X264_CSP_NONE ) { colorspace = alt_colorspace; h->bit_depth = alt_bit_depth; } // default to 8bit 4:2:0 if nothing is specified if( colorspace == X264_CSP_NONE ) { 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; 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" */ if( x264_is_regular_file( h->fh ) ) { uint64_t init_pos = ftell( h->fh ); fseek( h->fh, 0, SEEK_END ); uint64_t i_size = ftell( h->fh ); fseek( h->fh, init_pos, SEEK_SET ); info->num_frames = (i_size - h->seq_header_len) / h->frame_size; } *p_handle = h; return 0; }