Add mb_info API for signalling constant macroblocks
[x264/x264-sandbox.git] / input / y4m.c
1 /*****************************************************************************
2  * y4m.c: y4m input
3  *****************************************************************************
4  * Copyright (C) 2003-2012 x264 project
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *          Loren Merritt <lorenm@u.washington.edu>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
22  *
23  * This program is also available under a commercial proprietary license.
24  * For more information, contact us at licensing@x264.com.
25  *****************************************************************************/
26
27 #include "input.h"
28 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "y4m", __VA_ARGS__ )
29
30 typedef struct
31 {
32     FILE *fh;
33     int next_frame;
34     int seq_header_len;
35     int frame_header_len;
36     uint64_t frame_size;
37     uint64_t plane_size[3];
38 } y4m_hnd_t;
39
40 #define Y4M_MAGIC "YUV4MPEG2"
41 #define MAX_YUV4_HEADER 80
42 #define Y4M_FRAME_MAGIC "FRAME"
43 #define MAX_FRAME_HEADER 80
44
45 static int csp_string_to_int( char *csp_name )
46 {
47     int csp = X264_CSP_MAX;
48     if( !strncmp( "420", csp_name, 3 ) )
49         csp = X264_CSP_I420;
50     else if( !strncmp( "422", csp_name, 3 ) )
51         csp = X264_CSP_I422;
52     else if( !strncmp( "444", csp_name, 3 ) && strncmp( "444alpha", csp_name, 8 ) ) // only accept alphaless 4:4:4
53         csp = X264_CSP_I444;
54     return csp;
55 }
56
57 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
58 {
59     y4m_hnd_t *h = malloc( sizeof(y4m_hnd_t) );
60     int i;
61     uint32_t n, d;
62     char header[MAX_YUV4_HEADER+10];
63     char *tokend, *header_end;
64     int colorspace = X264_CSP_NONE;
65     int alt_colorspace = X264_CSP_NONE;
66     if( !h )
67         return -1;
68
69     h->next_frame = 0;
70     info->vfr = 0;
71
72     if( !strcmp( psz_filename, "-" ) )
73         h->fh = stdin;
74     else
75         h->fh = fopen(psz_filename, "rb");
76     if( h->fh == NULL )
77         return -1;
78
79     h->frame_header_len = strlen( Y4M_FRAME_MAGIC )+1;
80
81     /* Read header */
82     for( i = 0; i < MAX_YUV4_HEADER; i++ )
83     {
84         header[i] = fgetc( h->fh );
85         if( header[i] == '\n' )
86         {
87             /* Add a space after last option. Makes parsing "444" vs
88                "444alpha" easier. */
89             header[i+1] = 0x20;
90             header[i+2] = 0;
91             break;
92         }
93     }
94     if( i == MAX_YUV4_HEADER || strncmp( header, Y4M_MAGIC, strlen( Y4M_MAGIC ) ) )
95         return -1;
96
97     /* Scan properties */
98     header_end = &header[i+1]; /* Include space */
99     h->seq_header_len = i+1;
100     for( char *tokstart = &header[strlen( Y4M_MAGIC )+1]; tokstart < header_end; tokstart++ )
101     {
102         if( *tokstart == 0x20 )
103             continue;
104         switch( *tokstart++ )
105         {
106             case 'W': /* Width. Required. */
107                 info->width = strtol( tokstart, &tokend, 10 );
108                 tokstart=tokend;
109                 break;
110             case 'H': /* Height. Required. */
111                 info->height = strtol( tokstart, &tokend, 10 );
112                 tokstart=tokend;
113                 break;
114             case 'C': /* Color space */
115                 colorspace = csp_string_to_int( tokstart );
116                 tokstart = strchr( tokstart, 0x20 );
117                 break;
118             case 'I': /* Interlace type */
119                 switch( *tokstart++ )
120                 {
121                     case 't':
122                         info->interlaced = 1;
123                         info->tff = 1;
124                         break;
125                     case 'b':
126                         info->interlaced = 1;
127                         info->tff = 0;
128                         break;
129                     case 'm':
130                         info->interlaced = 1;
131                         break;
132                     //case '?':
133                     //case 'p':
134                     default:
135                         break;
136                 }
137                 break;
138             case 'F': /* Frame rate - 0:0 if unknown */
139                 if( sscanf( tokstart, "%u:%u", &n, &d ) == 2 && n && d )
140                 {
141                     x264_reduce_fraction( &n, &d );
142                     info->fps_num = n;
143                     info->fps_den = d;
144                 }
145                 tokstart = strchr( tokstart, 0x20 );
146                 break;
147             case 'A': /* Pixel aspect - 0:0 if unknown */
148                 /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
149                 if( sscanf( tokstart, "%u:%u", &n, &d ) == 2 && n && d )
150                 {
151                     x264_reduce_fraction( &n, &d );
152                     info->sar_width  = n;
153                     info->sar_height = d;
154                 }
155                 tokstart = strchr( tokstart, 0x20 );
156                 break;
157             case 'X': /* Vendor extensions */
158                 if( !strncmp( "YSCSS=", tokstart, 6 ) )
159                 {
160                     /* Older nonstandard pixel format representation */
161                     tokstart += 6;
162                     alt_colorspace = csp_string_to_int( tokstart );
163                 }
164                 tokstart = strchr( tokstart, 0x20 );
165                 break;
166         }
167     }
168
169     if( colorspace == X264_CSP_NONE )
170         colorspace = alt_colorspace;
171
172     // default to 4:2:0 if nothing is specified
173     if( colorspace == X264_CSP_NONE )
174         colorspace = X264_CSP_I420;
175
176     FAIL_IF_ERROR( colorspace <= X264_CSP_NONE || colorspace >= X264_CSP_MAX, "colorspace unhandled\n" )
177
178     info->thread_safe = 1;
179     info->num_frames  = 0;
180     info->csp         = colorspace;
181     h->frame_size     = h->frame_header_len;
182     for( i = 0; i < x264_cli_csps[info->csp].planes; i++ )
183     {
184         h->plane_size[i] = x264_cli_pic_plane_size( info->csp, info->width, info->height, i );
185         h->frame_size += h->plane_size[i];
186     }
187
188     /* Most common case: frame_header = "FRAME" */
189     if( x264_is_regular_file( h->fh ) )
190     {
191         uint64_t init_pos = ftell( h->fh );
192         fseek( h->fh, 0, SEEK_END );
193         uint64_t i_size = ftell( h->fh );
194         fseek( h->fh, init_pos, SEEK_SET );
195         info->num_frames = (i_size - h->seq_header_len) / h->frame_size;
196     }
197
198     *p_handle = h;
199     return 0;
200 }
201
202 static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h )
203 {
204     size_t slen = strlen( Y4M_FRAME_MAGIC );
205     int i = 0;
206     char header[16];
207
208     /* Read frame header - without terminating '\n' */
209     if( fread( header, 1, slen, h->fh ) != slen )
210         return -1;
211
212     header[slen] = 0;
213     FAIL_IF_ERROR( strncmp( header, Y4M_FRAME_MAGIC, slen ), "bad header magic (%"PRIx32" <=> %s)\n",
214                    M32(header), header )
215
216     /* Skip most of it */
217     while( i < MAX_FRAME_HEADER && fgetc( h->fh ) != '\n' )
218         i++;
219     FAIL_IF_ERROR( i == MAX_FRAME_HEADER, "bad frame header!\n" )
220     h->frame_size = h->frame_size - h->frame_header_len + i+slen+1;
221     h->frame_header_len = i+slen+1;
222
223     int error = 0;
224     for( i = 0; i < pic->img.planes && !error; i++ )
225         error |= fread( pic->img.plane[i], h->plane_size[i], 1, h->fh ) <= 0;
226     return error;
227 }
228
229 static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame )
230 {
231     y4m_hnd_t *h = handle;
232
233     if( i_frame > h->next_frame )
234     {
235         if( x264_is_regular_file( h->fh ) )
236             fseek( h->fh, h->frame_size * i_frame + h->seq_header_len, SEEK_SET );
237         else
238             while( i_frame > h->next_frame )
239             {
240                 if( read_frame_internal( pic, h ) )
241                     return -1;
242                 h->next_frame++;
243             }
244     }
245
246     if( read_frame_internal( pic, h ) )
247         return -1;
248
249     h->next_frame = i_frame+1;
250     return 0;
251 }
252
253 static int close_file( hnd_t handle )
254 {
255     y4m_hnd_t *h = handle;
256     if( !h || !h->fh )
257         return 0;
258     fclose( h->fh );
259     free( h );
260     return 0;
261 }
262
263 const cli_input_t y4m_input = { open_file, x264_cli_pic_alloc, read_frame, NULL, x264_cli_pic_clean, close_file };