Commit a84899e0 authored by Loren Merritt's avatar Loren Merritt

cli: support yuv4mpeg input.

patch by anonymous.



git-svn-id: svn://svn.videolan.org/x264/trunk@484 df754926-b1dd-0310-bc7b-ec298dee348c
parent e510c098
......@@ -395,6 +395,27 @@ void *x264_realloc( void *p, int i_size )
#endif
}
/****************************************************************************
* x264_reduce_fraction:
****************************************************************************/
void x264_reduce_fraction( int *n, int *d )
{
int a = *n;
int b = *d;
int c;
if( !a || !b )
return;
c = a % b;
while(c)
{
a = b;
b = c;
c = a % b;
}
*n /= b;
*d /= b;
}
/****************************************************************************
* x264_slurp_file:
****************************************************************************/
......
......@@ -120,6 +120,8 @@ char *x264_param2string( x264_param_t *p, int b_res );
/* log */
void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... );
void x264_reduce_fraction( int *n, int *d );
static inline int x264_clip3( int v, int i_min, int i_max )
{
return ( (v < i_min) ? i_min : (v > i_max) ? i_max : v );
......
......@@ -489,18 +489,9 @@ x264_t *x264_encoder_open ( x264_param_t *param )
{
int i_w = param->vui.i_sar_width;
int i_h = param->vui.i_sar_height;
int a = i_w, b = i_h;
while( b != 0 )
{
int t = a;
a = b;
b = t % b;
}
x264_reduce_fraction( &i_w, &i_h );
i_w /= a;
i_h /= a;
while( i_w > 65535 || i_h > 65535 )
{
i_w /= 2;
......@@ -525,6 +516,7 @@ x264_t *x264_encoder_open ( x264_param_t *param )
}
}
x264_reduce_fraction( &h->param.i_fps_num, &h->param.i_fps_den );
/* Init x264_t */
h->out.i_nal = 0;
......
......@@ -108,6 +108,206 @@ int close_file_yuv(hnd_t handle)
return fclose(h->fh);
}
/* YUV4MPEG2 raw 420 yuv file operation */
typedef struct {
FILE *fh;
int width, height;
int next_frame;
int seq_header_len, frame_header_len;
int frame_size;
} y4m_input_t;
#define Y4M_MAGIC "YUV4MPEG2"
#define MAX_YUV4_HEADER 80
#define Y4M_FRAME_MAGIC "FRAME"
#define MAX_FRAME_HEADER 80
int open_file_y4m( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
{
int i, n, d;
int interlaced;
char header[MAX_YUV4_HEADER+10];
char *tokstart, *tokend, *header_end;
y4m_input_t *h = malloc(sizeof(y4m_input_t));
h->next_frame = 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( tokstart = &header[strlen(Y4M_MAGIC)+1]; tokstart < header_end; tokstart++ )
{
if(*tokstart==0x20) continue;
switch(*tokstart++)
{
case 'W': /* Width. Required. */
h->width = p_param->i_width = strtol(tokstart, &tokend, 10);
tokstart=tokend;
break;
case 'H': /* Height. Required. */
h->height = p_param->i_height = strtol(tokstart, &tokend, 10);
tokstart=tokend;
break;
case 'C': /* Color space */
if( strncmp("420", tokstart, 3) )
{
fprintf(stderr, "Colorspace unhandled\n");
return -1;
}
tokstart = strchr(tokstart, 0x20);
break;
case 'I': /* Interlace type */
switch(*tokstart++)
{
case 'p': interlaced = 0; break;
case '?':
case 't':
case 'b':
case 'm':
default: interlaced = 1;
fprintf(stderr, "Warning, this sequence might be interlaced\n");
}
break;
case 'F': /* Frame rate - 0:0 if unknown */
if( sscanf(tokstart, "%d:%d", &n, &d) == 2 && n && d )
{
x264_reduce_fraction( &n, &d );
p_param->i_fps_num = n;
p_param->i_fps_den = d;
}
tokstart = strchr(tokstart, 0x20);
break;
case 'A': /* Pixel aspect - 0:0 if unknown */
if( sscanf(tokstart, "%d:%d", &n, &d) == 2 && n && d )
{
x264_reduce_fraction( &n, &d );
p_param->vui.i_sar_width = n;
p_param->vui.i_sar_height = d;
}
tokstart = strchr(tokstart, 0x20);
break;
case 'X': /* Vendor extensions */
if( !strncmp("YSCSS=",tokstart,6) )
{
/* Older nonstandard pixel format representation */
tokstart += 6;
if( strncmp("420JPEG",tokstart,7) &&
strncmp("420MPEG2",tokstart,8) &&
strncmp("420PALDV",tokstart,8) )
{
fprintf(stderr, "Unsupported extended colorspace\n");
return -1;
}
}
tokstart = strchr(tokstart, 0x20);
break;
}
}
fprintf(stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
h->width, h->height, p_param->i_fps_num, p_param->i_fps_den,
p_param->vui.i_sar_width, p_param->vui.i_sar_height);
*p_handle = (hnd_t)h;
return 0;
}
/* Most common case: frame_header = "FRAME" */
int get_frame_total_y4m( hnd_t handle )
{
y4m_input_t *h = handle;
int i_frame_total = 0;
off_t init_pos = ftell(h->fh);
if( !fseek( h->fh, 0, SEEK_END ) )
{
uint64_t i_size = ftell( h->fh );
fseek( h->fh, init_pos, SEEK_SET );
i_frame_total = (int)((i_size - h->seq_header_len) /
(3*(h->width*h->height)/2+h->frame_header_len));
}
return i_frame_total;
}
int read_frame_y4m( x264_picture_t *p_pic, hnd_t handle, int i_frame )
{
int slen = strlen(Y4M_FRAME_MAGIC);
int i = 0;
char header[16];
y4m_input_t *h = handle;
if( i_frame != h->next_frame )
{
if (fseek(h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
+ h->seq_header_len, SEEK_SET))
return -1;
}
/* Read frame header - without terminating '\n' */
if (fread(header, 1, slen, h->fh) != slen)
return -1;
header[slen] = 0;
if (strncmp(header, Y4M_FRAME_MAGIC, slen))
{
fprintf(stderr, "Bad header magic (%08X <=> %s)\n",
*((uint32_t*)header), header);
return -1;
}
/* Skip most of it */
while (i<MAX_FRAME_HEADER && fgetc(h->fh) != '\n')
i++;
if (i == MAX_FRAME_HEADER)
{
fprintf(stderr, "Bad frame header!\n");
return -1;
}
h->frame_header_len = i+slen+1;
if( fread(p_pic->img.plane[0], 1, h->width*h->height, h->fh) <= 0
|| fread(p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh) <= 0
|| fread(p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh) <= 0)
return -1;
h->next_frame = i_frame+1;
return 0;
}
int close_file_y4m(hnd_t handle)
{
y4m_input_t *h = handle;
if( !h || !h->fh )
return 0;
return fclose(h->fh);
}
/* avs/avi input file support under cygwin */
......
......@@ -8,6 +8,11 @@ int get_frame_total_yuv( hnd_t handle );
int read_frame_yuv( x264_picture_t *p_pic, hnd_t handle, int i_frame );
int close_file_yuv( hnd_t handle );
int open_file_y4m( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
int get_frame_total_y4m( hnd_t handle );
int read_frame_y4m( x264_picture_t *p_pic, hnd_t handle, int i_frame );
int close_file_y4m( hnd_t handle );
#ifdef AVIS_INPUT
int open_file_avis( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
int get_frame_total_avis( hnd_t handle );
......
......@@ -133,6 +133,7 @@ static void Help( x264_param_t *defaults )
"Syntax: x264 [options] -o outfile infile [widthxheight]\n"
"\n"
"Infile can be raw YUV 4:2:0 (in which case resolution is required),\n"
" or YUV4MPEG 4:2:0 (*.y4m),\n"
" or AVI or Avisynth if compiled with AVIS support (%s).\n"
"Outfile type is selected by filename:\n"
" .264 -> Raw bytestream\n"
......@@ -360,6 +361,7 @@ static int Parse( int argc, char **argv,
x264_param_t defaults = *param;
char *psz;
int b_avis = 0;
int b_y4m = 0;
int b_thread_input = 0;
memset( opt, 0, sizeof(cli_opt_t) );
......@@ -947,8 +949,9 @@ static int Parse( int argc, char **argv,
if( !strncasecmp( psz, ".avi", 4 ) || !strncasecmp( psz, ".avs", 4 ) )
b_avis = 1;
if( !b_avis && ( !param->i_width || !param->i_height ) )
if( !strncasecmp( psz, ".y4m", 4 ) )
b_y4m = 1;
if( !(b_avis || b_y4m) && ( !param->i_width || !param->i_height ) )
{
Help( &defaults );
return -1;
......@@ -969,6 +972,14 @@ static int Parse( int argc, char **argv,
return -1;
#endif
}
if ( b_y4m )
{
p_open_infile = open_file_y4m;
p_get_frame_total = get_frame_total_y4m;
p_read_frame = read_frame_y4m;
p_close_infile = close_file_y4m;
}
if( p_open_infile( psz_filename, &opt->hin, param ) )
{
fprintf( stderr, "could not open input file '%s'\n", psz_filename );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment