Add help message.
[frameshot.git] / input / y4m.c
blob014583517d844e9ff8c5a28c0cb1699d3d695f09
1 #include <stdio.h>
2 #include <inttypes.h>
3 #include <malloc.h>
4 #include <string.h>
6 #include "common.h"
7 #include "utils.h"
8 #include "y4m.h"
10 /* YUV4MPEG2 raw 420 yuv file operation */
11 typedef struct {
12 FILE *fh;
13 int width, height;
14 int par_width, par_height;
15 int next_frame;
16 int seq_header_len, frame_header_len;
17 int frame_size;
18 int csp;
19 int fps_num, fps_den;
20 } y4m_input_t;
22 #define Y4M_MAGIC "YUV4MPEG2"
23 #define MAX_YUV4_HEADER 80
24 #define Y4M_FRAME_MAGIC "FRAME"
25 #define MAX_FRAME_HEADER 80
27 int open_file_y4m( char *psz_filename, hnd_t *p_handle )
29 int i, n, d;
30 int interlaced;
31 char header[MAX_YUV4_HEADER+10];
32 char *tokstart, *tokend, *header_end;
33 y4m_input_t *h = calloc(1, sizeof(*h));
35 h->next_frame = 0;
37 if( !strcmp(psz_filename, "-") )
38 h->fh = stdin;
39 else
40 h->fh = fopen(psz_filename, "rb");
41 if( h->fh == NULL )
42 return -1;
44 h->frame_header_len = strlen(Y4M_FRAME_MAGIC)+1;
46 /* Read header */
47 for( i=0; i<MAX_YUV4_HEADER; i++ )
49 header[i] = fgetc(h->fh);
50 if( header[i] == '\n' )
52 /* Add a space after last option. Makes parsing "444" vs
53 "444alpha" easier. */
54 header[i+1] = 0x20;
55 header[i+2] = 0;
56 break;
59 if( i == MAX_YUV4_HEADER || strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)) )
60 return -1;
62 /* Scan properties */
63 header_end = &header[i+1]; /* Include space */
64 h->seq_header_len = i+1;
65 for( tokstart = &header[strlen(Y4M_MAGIC)+1]; tokstart < header_end; tokstart++ )
67 if(*tokstart==0x20) continue;
68 switch(*tokstart++)
70 case 'W': /* Width. Required. */
71 h->width = strtol(tokstart, &tokend, 10);
72 tokstart=tokend;
73 break;
74 case 'H': /* Height. Required. */
75 h->height = strtol(tokstart, &tokend, 10);
76 tokstart=tokend;
77 break;
78 case 'C': /* Color space */
79 if( strncmp("420", tokstart, 3) )
81 fprintf(stderr, "Colorspace unhandled\n");
82 return -1;
84 tokstart = strchr(tokstart, 0x20);
85 break;
86 case 'I': /* Interlace type */
87 switch(*tokstart++)
89 case 'p': interlaced = 0; break;
90 case '?':
91 case 't':
92 case 'b':
93 case 'm':
94 default: interlaced = 1;
95 fprintf(stderr, "Warning, this sequence might be interlaced\n");
97 break;
98 case 'F': /* Frame rate - 0:0 if unknown */
99 /* Frame rate in unimportant. */
100 if( sscanf(tokstart, "%d:%d", &n, &d) == 2 && n && d )
102 reduce_fraction( &n, &d );
103 h->fps_num = n;
104 h->fps_den = d;
106 tokstart = strchr(tokstart, 0x20);
107 break;
108 case 'A': /* Pixel aspect - 0:0 if unknown */
109 /* Don't override the aspect ratio if sar has been explicitly set on the commandline. */
110 if( sscanf(tokstart, "%d:%d", &n, &d) == 2 && n && d )
112 reduce_fraction( &n, &d );
113 h->par_width = n;
114 h->par_height = d;
116 tokstart = strchr(tokstart, 0x20);
117 break;
118 case 'X': /* Vendor extensions */
119 if( !strncmp("YSCSS=",tokstart,6) )
121 /* Older nonstandard pixel format representation */
122 tokstart += 6;
123 if( strncmp("420JPEG",tokstart,7) &&
124 strncmp("420MPEG2",tokstart,8) &&
125 strncmp("420PALDV",tokstart,8) )
127 fprintf(stderr, "Unsupported extended colorspace\n");
128 return -1;
131 tokstart = strchr(tokstart, 0x20);
132 break;
136 fprintf(stderr, "yuv4mpeg: %ix%i@%i/%ifps, %i:%i\n",
137 h->width, h->height, h->fps_num, h->fps_den,
138 h->par_width, h->par_height);
140 *p_handle = (hnd_t)h;
141 return 0;
144 int read_frame_y4m( hnd_t handle, picture_t *p_pic, int i_frame )
146 int slen = strlen(Y4M_FRAME_MAGIC);
147 int i = 0;
148 char header[16];
149 y4m_input_t *h = handle;
151 if( i_frame != h->next_frame )
153 if (fseek(h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
154 + h->seq_header_len, SEEK_SET))
155 return -1;
158 /* Read frame header - without terminating '\n' */
159 if (fread(header, 1, slen, h->fh) != slen)
160 return -1;
162 header[slen] = 0;
163 if (strncmp(header, Y4M_FRAME_MAGIC, slen))
165 fprintf(stderr, "Bad header magic (%"PRIx32" <=> %s)\n",
166 *((uint32_t*)header), header);
167 return -1;
170 /* Skip most of it */
171 while (i<MAX_FRAME_HEADER && fgetc(h->fh) != '\n')
172 i++;
173 if (i == MAX_FRAME_HEADER)
175 fprintf(stderr, "Bad frame header!\n");
176 return -1;
178 h->frame_header_len = i+slen+1;
180 if( fread(p_pic->img.plane[0], 1, h->width*h->height, h->fh) <= 0
181 || fread(p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh) <= 0
182 || fread(p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh) <= 0)
183 return -1;
185 h->next_frame = i_frame+1;
187 return 0;
190 int close_file_y4m(hnd_t handle)
192 y4m_input_t *h = handle;
193 if( !h || !h->fh )
194 return 0;
195 fclose( h->fh );
196 free( h );
197 return 0;