1 /*****************************************************************************
2 * y4m.c: YUV4MPEG stream parser.
3 *****************************************************************************
6 * Authors: x264 developers
7 * Nathan Caldwell <saintdev@gmail.com>
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.
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.
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 *****************************************************************************/
34 /* Most of this is from x264 */
36 /* YUV4MPEG2 raw 420 yuv file operation */
40 int par_width
, par_height
;
42 int seq_header_len
, frame_header_len
;
48 #define Y4M_MAGIC "YUV4MPEG2"
49 #define MAX_YUV4_HEADER 80
50 #define Y4M_FRAME_MAGIC "FRAME"
51 #define MAX_FRAME_HEADER 80
53 int open_file_y4m( char *psz_filename
, hnd_t
*p_handle
, config_t
*p_config
)
57 char header
[MAX_YUV4_HEADER
+10];
58 char *tokstart
, *tokend
, *header_end
;
59 y4m_input_t
*h
= calloc(1, sizeof(*h
));
63 if( !strcmp(psz_filename
, "-") )
66 h
->fh
= fopen(psz_filename
, "rb");
70 h
->frame_header_len
= strlen(Y4M_FRAME_MAGIC
)+1;
73 for( i
=0; i
<MAX_YUV4_HEADER
; i
++ )
75 header
[i
] = fgetc(h
->fh
);
76 if( header
[i
] == '\n' )
78 /* Add a space after last option. Makes parsing "444" vs
85 if( i
== MAX_YUV4_HEADER
|| strncmp(header
, Y4M_MAGIC
, strlen(Y4M_MAGIC
)) )
89 header_end
= &header
[i
+1]; /* Include space */
90 h
->seq_header_len
= i
+1;
91 for( tokstart
= &header
[strlen(Y4M_MAGIC
)+1]; tokstart
< header_end
; tokstart
++ )
93 if(*tokstart
==0x20) continue;
96 case 'W': /* Width. Required. */
97 h
->width
= p_config
->i_width
= strtol(tokstart
, &tokend
, 10);
100 case 'H': /* Height. Required. */
101 h
->height
= p_config
->i_height
= strtol(tokstart
, &tokend
, 10);
104 case 'C': /* Color space */
105 if( strncmp("420", tokstart
, 3) )
107 fprintf(stderr
, "Colorspace unhandled\n");
110 tokstart
= strchr(tokstart
, 0x20);
112 case 'I': /* Interlace type */
115 case 'p': interlaced
= 0; break;
120 default: interlaced
= 1;
121 fprintf(stderr
, "Warning, this sequence might be interlaced\n");
124 case 'F': /* Frame rate - 0:0 if unknown */
125 /* Frame rate in unimportant. */
126 if( sscanf(tokstart
, "%d:%d", &n
, &d
) == 2 && n
&& d
)
128 reduce_fraction( &n
, &d
);
132 tokstart
= strchr(tokstart
, 0x20);
134 case 'A': /* Pixel aspect - 0:0 if unknown */
135 /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
136 if( sscanf(tokstart
, "%d:%d", &n
, &d
) == 2 && n
&& d
)
138 reduce_fraction( &n
, &d
);
142 tokstart
= strchr(tokstart
, 0x20);
144 case 'X': /* Vendor extensions */
145 if( !strncmp("YSCSS=",tokstart
,6) )
147 /* Older nonstandard pixel format representation */
149 if( strncmp("420JPEG",tokstart
,7) &&
150 strncmp("420MPEG2",tokstart
,8) &&
151 strncmp("420PALDV",tokstart
,8) )
153 fprintf(stderr
, "Unsupported extended colorspace\n");
157 tokstart
= strchr(tokstart
, 0x20);
162 fprintf(stderr
, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
163 h
->width
, h
->height
, h
->fps_num
, h
->fps_den
,
164 h
->par_width
, h
->par_height
);
166 *p_handle
= (hnd_t
)h
;
170 int read_frame_y4m( hnd_t handle
, picture_t
*p_pic
, int i_frame
)
172 int slen
= strlen(Y4M_FRAME_MAGIC
);
175 y4m_input_t
*h
= handle
;
177 if( i_frame
!= h
->next_frame
)
179 if (fseek(h
->fh
, (uint64_t)i_frame
*(3*(h
->width
*h
->height
)/2+h
->frame_header_len
)
180 + h
->seq_header_len
, SEEK_SET
))
184 /* Read frame header - without terminating '\n' */
185 if (fread(header
, 1, slen
, h
->fh
) != slen
)
189 if (strncmp(header
, Y4M_FRAME_MAGIC
, slen
))
191 fprintf(stderr
, "Bad header magic (%"PRIx32
" <=> %s)\n",
192 *((uint32_t*)header
), header
);
196 /* Skip most of it */
197 while (i
<MAX_FRAME_HEADER
&& fgetc(h
->fh
) != '\n')
199 if (i
== MAX_FRAME_HEADER
)
201 fprintf(stderr
, "Bad frame header!\n");
204 h
->frame_header_len
= i
+slen
+1;
206 if( fread(p_pic
->img
.plane
[0], 1, h
->width
*h
->height
, h
->fh
) <= 0
207 || fread(p_pic
->img
.plane
[1], 1, h
->width
* h
->height
/ 4, h
->fh
) <= 0
208 || fread(p_pic
->img
.plane
[2], 1, h
->width
* h
->height
/ 4, h
->fh
) <= 0)
211 p_pic
->i_pts
= i_frame
;
212 h
->next_frame
= i_frame
+1;
217 int close_file_y4m(hnd_t handle
)
219 y4m_input_t
*h
= handle
;