]> granicus.if.org Git - libx264/commitdiff
cli: support yuv4mpeg input.
authorLoren Merritt <pengvado@videolan.org>
Sun, 26 Mar 2006 20:40:20 +0000 (20:40 +0000)
committerLoren Merritt <pengvado@videolan.org>
Sun, 26 Mar 2006 20:40:20 +0000 (20:40 +0000)
patch by anonymous.

git-svn-id: svn://svn.videolan.org/x264/trunk@484 df754926-b1dd-0310-bc7b-ec298dee348c

common/common.c
common/common.h
encoder/encoder.c
muxers.c
muxers.h
x264.c

index 5f560d7874f6ba92dc258939bcf2117f8480bce3..e4d5ef69e9c10821873e4bc9ac85f6bed87574bb 100644 (file)
@@ -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:
  ****************************************************************************/
index 3465cb657cf01d436867607c15ce2570e28d4e29..b9fbae44482c72b6f99bb848dc768aace02403ac 100644 (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 );
index bdfd74b978fb5dda5ba4eb8a31910700fcb90f54..88f1bf0f6e2db6f2207cbe415810fc538aac925e 100644 (file)
@@ -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;
index f8526974697b05347af4bb268277f58d2fd6a7a6..97a513bb2ecc7547e21141f3f27ff7566cd96671 100644 (file)
--- a/muxers.c
+++ b/muxers.c
@@ -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 */
 
index e6d3d2ea18e7025e7baf62c78df80e1d10920eb7..7ce84afb9181443e933b95abf00bf2219ea05266 100644 (file)
--- a/muxers.h
+++ b/muxers.h
@@ -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 );
diff --git a/x264.c b/x264.c
index 2ffcdfcb6e2db33b43d2bfc277d77decdf030328..6f9a4858e70936c7a71c20c60272ff0d82e59455 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -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 );