X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=input%2Fy4m.c;h=b8893ab1ef8eccdfef1abb5cbd7e27a4c3ae18b1;hb=3b70645597bea052d2398005bc723212aeea6875;hp=060da0d39b2b19071c8911400a888706240fe694;hpb=38a5268dbec56adea750e05c4981f3bbb176e735;p=x264 diff --git a/input/y4m.c b/input/y4m.c index 060da0d3..b8893ab1 100644 --- a/input/y4m.c +++ b/input/y4m.c @@ -1,7 +1,7 @@ /***************************************************************************** * y4m.c: y4m input ***************************************************************************** - * Copyright (C) 2003-2015 x264 project + * Copyright (C) 2003-2016 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -36,6 +36,8 @@ typedef struct uint64_t frame_size; uint64_t plane_size[3]; int bit_depth; + cli_mmap_t mmap; + int use_mmap; } y4m_hnd_t; #define Y4M_MAGIC "YUV4MPEG2" @@ -97,8 +99,8 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c break; } } - if( i == MAX_YUV4_HEADER || strncmp( header, Y4M_MAGIC, sizeof(Y4M_MAGIC)-1 ) ) - return -1; + FAIL_IF_ERROR( strncmp( header, Y4M_MAGIC, sizeof(Y4M_MAGIC)-1 ), "bad sequence header magic\n" ) + FAIL_IF_ERROR( i == MAX_YUV4_HEADER, "bad sequence header length\n" ) /* Scan properties */ header_end = &header[i+1]; /* Include space */ @@ -221,6 +223,10 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c 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; + + /* 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; @@ -231,26 +237,44 @@ static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h, int bit_depth_uc ) { static const size_t slen = sizeof(Y4M_FRAME_MAGIC)-1; int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); - int i = 0; - char header[16]; - - /* Read frame header - without terminating '\n' */ - if( fread( header, 1, slen, h->fh ) != slen ) - return -1; + int i = sizeof(Y4M_FRAME_MAGIC); + char header_buf[16]; + char *header; - header[slen] = 0; - FAIL_IF_ERROR( strncmp( header, Y4M_FRAME_MAGIC, slen ), "bad header magic (%"PRIx32" <=> %s)\n", - M32(header), header ) - - /* Skip most of it */ - while( i < MAX_FRAME_HEADER && fgetc( h->fh ) != '\n' ) - i++; - FAIL_IF_ERROR( i == MAX_FRAME_HEADER, "bad frame header!\n" ) + /* Verify that the frame header is valid */ + if( h->use_mmap ) + { + header = (char*)pic->img.plane[0]; + pic->img.plane[0] += h->frame_header_len; + + /* If the header length has changed between frames the size of the mapping will be invalid. + * It might be possible to work around it, but I'm not aware of any tool beside fuzzers that + * produces y4m files with variable-length frame headers so just error out if that happens. */ + while( i <= h->frame_header_len && header[i-1] != '\n' ) + i++; + FAIL_IF_ERROR( i != h->frame_header_len, "bad frame header length\n" ) + } + else + { + header = header_buf; + if( fread( header, 1, slen, h->fh ) != slen ) + return -1; + while( i <= MAX_FRAME_HEADER && fgetc( h->fh ) != '\n' ) + i++; + FAIL_IF_ERROR( i > MAX_FRAME_HEADER, "bad frame header length\n" ) + } + FAIL_IF_ERROR( memcmp( header, Y4M_FRAME_MAGIC, slen ), "bad frame header magic\n" ) - int error = 0; - for( i = 0; i < pic->img.planes && !error; i++ ) + for( i = 0; i < pic->img.planes; i++ ) { - error |= fread( pic->img.plane[i], pixel_depth, h->plane_size[i], h->fh ) != h->plane_size[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 @@ -262,14 +286,20 @@ static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h, int bit_depth_uc ) plane[j] = plane[j] << lshift; } } - return error; + return 0; } static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame ) { y4m_hnd_t *h = handle; - if( i_frame > h->next_frame ) + if( h->use_mmap ) + { + pic->img.plane[0] = x264_cli_mmap( &h->mmap, h->frame_size * i_frame + h->seq_header_len, h->frame_size ); + if( !pic->img.plane[0] ) + return -1; + } + else if( i_frame > h->next_frame ) { if( x264_is_regular_file( h->fh ) ) fseek( h->fh, h->frame_size * i_frame + h->seq_header_len, SEEK_SET ); @@ -289,14 +319,39 @@ static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame ) return 0; } +static int release_frame( cli_pic_t *pic, hnd_t handle ) +{ + y4m_hnd_t *h = handle; + if( h->use_mmap ) + return x264_cli_munmap( &h->mmap, pic->img.plane[0] - h->frame_header_len, h->frame_size ); + return 0; +} + +static int picture_alloc( cli_pic_t *pic, hnd_t handle, int csp, int width, int height ) +{ + y4m_hnd_t *h = handle; + return (h->use_mmap ? x264_cli_pic_init_noalloc : x264_cli_pic_alloc)( pic, csp, width, height ); +} + +static void picture_clean( cli_pic_t *pic, hnd_t handle ) +{ + y4m_hnd_t *h = handle; + if( h->use_mmap ) + memset( pic, 0, sizeof(cli_pic_t) ); + else + x264_cli_pic_clean( pic ); +} + static int close_file( hnd_t handle ) { y4m_hnd_t *h = handle; if( !h || !h->fh ) return 0; + if( h->use_mmap ) + x264_cli_mmap_close( &h->mmap ); fclose( h->fh ); free( h ); return 0; } -const cli_input_t y4m_input = { open_file, x264_cli_pic_alloc, read_frame, NULL, x264_cli_pic_clean, close_file }; +const cli_input_t y4m_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };