Line data Source code
1 : /*
2 : * Copyright(c) 2019 Intel Corporation
3 : * SPDX - License - Identifier: BSD - 2 - Clause - Patent
4 : */
5 :
6 : #include "EbAppString.h"
7 : #include "EbAppInputy4m.h"
8 : #define YFM_HEADER_MAX 80
9 : #define YUV4MPEG2_IND_SIZE 9
10 : #define PRINT_HEADER 0
11 : #define CHROMA_MAX 4
12 :
13 : /* copy a string until a specified character or a new line is found */
14 10 : char* copyUntilCharacterOrNewLine(char *src, char *dst, char chr){
15 10 : rsize_t count = 0;
16 10 : char * src_init = src;
17 :
18 34 : while (*src != chr && *src != '\n') {
19 24 : src++;
20 24 : count++;
21 : }
22 :
23 10 : EB_STRNCPY(dst, YFM_HEADER_MAX, src_init, count);
24 :
25 10 : return src;
26 : }
27 :
28 : /* reads the y4m header and parses the input parameters */
29 2 : int32_t read_y4m_header(EbConfig *cfg){
30 : FILE *ptr_in;
31 : char buffer[YFM_HEADER_MAX];
32 : char *fresult, *tokstart, *tokend, format_str[YFM_HEADER_MAX];
33 2 : uint32_t bitdepth = 8, width = 0, height = 0, fr_n = 0,
34 2 : fr_d = 0, aspect_n, aspect_d;
35 2 : char chroma[CHROMA_MAX] = "420", scan_type = 'p';
36 2 : EbBool interlaced = EB_TRUE;
37 :
38 : /* pointer to the input file */
39 2 : ptr_in = cfg->input_file;
40 :
41 : /* get first line after YUV4MPEG2 */
42 2 : fresult = fgets(buffer, sizeof(buffer), ptr_in);
43 2 : if(fresult==NULL)
44 0 : return EB_ErrorBadParameter;
45 :
46 : /* print header */
47 : if(PRINT_HEADER) {
48 : printf("y4m header:");
49 : fputs(buffer, stdout);
50 : }
51 :
52 : /* read header parameters */
53 2 : tokstart = &(buffer[0]);
54 :
55 32 : while (*tokstart != '\0') {
56 30 : if (*tokstart == 0x20) {
57 14 : tokstart++;
58 14 : continue;
59 : }
60 :
61 16 : switch (*tokstart++) {
62 2 : case 'W': /* width, required. */
63 2 : width = (uint32_t)strtol(tokstart, &tokend, 10);
64 : if(PRINT_HEADER)
65 : printf("width = %d\n", width);
66 2 : tokstart = tokend;
67 2 : break;
68 2 : case 'H': /* height, required. */
69 2 : height = (uint32_t)strtol(tokstart, &tokend, 10);
70 : if(PRINT_HEADER)
71 : printf("height = %d\n", height);
72 2 : tokstart = tokend;
73 2 : break;
74 2 : case 'I': /* scan type, not required, default: 'p' */
75 2 : switch (*tokstart++) {
76 2 : case 'p':
77 2 : interlaced = EB_FALSE;
78 2 : scan_type = 'p';
79 2 : break;
80 0 : case 't':
81 0 : interlaced = EB_TRUE;
82 0 : scan_type = 't';
83 0 : break;
84 0 : case 'b':
85 0 : interlaced = EB_TRUE;
86 0 : scan_type = 'b';
87 0 : break;
88 0 : case '?':
89 : default:
90 0 : fprintf(cfg->error_log_file, "interlace type not supported\n");
91 0 : return EB_ErrorBadParameter;
92 : }
93 : if(PRINT_HEADER)
94 : printf("scan_type = %c\n", scan_type);
95 2 : break;
96 2 : case 'C': /* color space, not required: default "420" */
97 2 : tokstart = copyUntilCharacterOrNewLine(tokstart, format_str, 0x20);
98 2 : if (EB_STRCMP("420mpeg2", format_str) == 0) {
99 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
100 : // chroma left
101 0 : bitdepth = 8;
102 2 : } else if (EB_STRCMP("420paldv", format_str) == 0) {
103 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
104 : // chroma top-left
105 0 : bitdepth = 8;
106 2 : }else if (EB_STRCMP("420jpeg", format_str) == 0) {
107 2 : EB_STRCPY(chroma, CHROMA_MAX, "420");
108 : // chroma center
109 2 : bitdepth = 8;
110 0 : } else if (EB_STRCMP("420p16", format_str) == 0) {
111 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
112 0 : bitdepth = 16;
113 0 : } else if (EB_STRCMP("422p16", format_str) == 0) {
114 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
115 0 : bitdepth = 16;
116 0 : } else if (EB_STRCMP("444p16", format_str) == 0) {
117 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
118 0 : bitdepth = 16;
119 0 : } else if (EB_STRCMP("420p14", format_str) == 0) {
120 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
121 0 : bitdepth = 14;
122 0 : } else if (EB_STRCMP("422p14", format_str) == 0) {
123 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
124 0 : bitdepth = 14;
125 0 : } else if (EB_STRCMP("444p14", format_str) == 0) {
126 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
127 0 : bitdepth = 14;
128 0 : } else if (EB_STRCMP("420p12", format_str) == 0) {
129 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
130 0 : bitdepth = 12;
131 0 : } else if (EB_STRCMP("422p12", format_str) == 0) {
132 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
133 0 : bitdepth = 12;
134 0 : } else if (EB_STRCMP("444p12", format_str) == 0) {
135 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
136 0 : bitdepth = 12;
137 0 : } else if (EB_STRCMP("420p10", format_str) == 0) {
138 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
139 0 : bitdepth = 10;
140 0 : } else if (EB_STRCMP("422p10", format_str) == 0) {
141 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
142 0 : bitdepth = 10;
143 0 : } else if (EB_STRCMP("444p10", format_str) == 0) {
144 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
145 0 : bitdepth = 10;
146 0 : } else if (EB_STRCMP("420p9", format_str) == 0) {
147 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
148 0 : bitdepth = 9;
149 0 : } else if (EB_STRCMP("422p9", format_str) == 0) {
150 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
151 0 : bitdepth = 9;
152 0 : } else if (EB_STRCMP("444p9", format_str) == 0) {
153 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
154 0 : bitdepth = 9;
155 0 : } else if (EB_STRCMP("420", format_str) == 0) {
156 0 : EB_STRCPY(chroma, CHROMA_MAX, "420");
157 0 : bitdepth = 8;
158 0 : } else if (EB_STRCMP("411", format_str) == 0) {
159 0 : EB_STRCPY(chroma, CHROMA_MAX, "411");
160 0 : bitdepth = 8;
161 0 : } else if (EB_STRCMP("422", format_str) == 0) {
162 0 : EB_STRCPY(chroma, CHROMA_MAX, "422");
163 0 : bitdepth = 8;
164 0 : } else if (EB_STRCMP("444", format_str) == 0) {
165 0 : EB_STRCPY(chroma, CHROMA_MAX, "444");
166 0 : bitdepth = 8;
167 0 : } else if (EB_STRCMP("mono16", format_str) == 0) {
168 0 : EB_STRCPY(chroma, CHROMA_MAX, "400");
169 0 : bitdepth = 16;
170 0 : } else if (EB_STRCMP("mono12", format_str) == 0) {
171 0 : EB_STRCPY(chroma, CHROMA_MAX, "400");
172 0 : bitdepth = 12;
173 0 : } else if (EB_STRCMP("mono10", format_str) == 0) {
174 0 : EB_STRCPY(chroma, CHROMA_MAX, "400");
175 0 : bitdepth = 10;
176 0 : } else if (EB_STRCMP("mono9", format_str) == 0) {
177 0 : EB_STRCPY(chroma, CHROMA_MAX, "400");
178 0 : bitdepth = 9;
179 0 : } else if (EB_STRCMP("mono", format_str) == 0) {
180 0 : EB_STRCPY(chroma, CHROMA_MAX, "400");
181 0 : bitdepth = 8;
182 : } else {
183 0 : fprintf(cfg->error_log_file, "chroma format not supported\n");
184 0 : return EB_ErrorBadParameter;
185 : }
186 : if(PRINT_HEADER)
187 : printf("chroma = %s, bitdepth = %d\n", chroma, bitdepth);
188 2 : break;
189 2 : case 'F': /* frame rate, required */
190 2 : tokstart = copyUntilCharacterOrNewLine(tokstart, format_str, ':');
191 2 : fr_n = (uint32_t) strtol(format_str, (char **)NULL, 10);
192 2 : tokstart++;
193 2 : tokstart = copyUntilCharacterOrNewLine(tokstart, format_str, 0x20);
194 2 : fr_d = (uint32_t) strtol(format_str, (char **)NULL, 10);
195 : if(PRINT_HEADER) {
196 : printf("framerate_n = %d\n", fr_n);
197 : printf("framerate_d = %d\n", fr_d);
198 : }
199 2 : break;
200 2 : case 'A': /* aspect ratio, not required */
201 2 : tokstart = copyUntilCharacterOrNewLine(tokstart, format_str, ':');
202 2 : aspect_n = (uint32_t) strtol(format_str, (char **)NULL, 10);
203 2 : tokstart++;
204 2 : tokstart = copyUntilCharacterOrNewLine(tokstart, format_str, 0x20);
205 2 : aspect_d = (uint32_t) strtol(format_str, (char **)NULL, 10);
206 : if(PRINT_HEADER) {
207 : printf("aspect_n = %d\n", aspect_n);
208 : printf("aspect_d = %d\n", aspect_d);
209 : }
210 2 : break;
211 4 : default:
212 : /* Unknown section: skip it */
213 48 : while (*tokstart != 0x20 && *tokstart != '\0')
214 44 : tokstart++;
215 4 : break;
216 : }
217 : }
218 :
219 : /* Check that we did not try to parse further the end of the header string */
220 2 : assert(fresult + strlen(fresult) == tokstart);
221 :
222 : /*check if required parameters were read*/
223 2 : if(width == 0) {
224 0 : fprintf(cfg->error_log_file, "width not found in y4m header\n");
225 0 : return EB_ErrorBadParameter;
226 : }
227 2 : if(height == 0) {
228 0 : fprintf(cfg->error_log_file, "height not found in y4m header\n");
229 0 : return EB_ErrorBadParameter;
230 : }
231 2 : if(fr_n == 0 || fr_d == 0) {
232 0 : fprintf(cfg->error_log_file, "frame rate not found in y4m header\n");
233 0 : return EB_ErrorBadParameter;
234 : }
235 :
236 : /* Assign parameters to cfg */
237 2 : cfg->source_width = width;
238 2 : cfg->source_height = height;
239 2 : cfg->frame_rate_numerator = fr_n;
240 2 : cfg->frame_rate_denominator = fr_d;
241 2 : cfg->frame_rate = fr_n/fr_d;
242 2 : cfg->encoder_bit_depth = bitdepth;
243 2 : cfg->interlaced_video = interlaced;
244 : /* TODO: when implemented, need to set input bit depth
245 : (instead of the encoder bit depth) and chroma format */
246 :
247 2 : return EB_ErrorNone;
248 : }
249 :
250 : /* read next line which contains the "FRAME" delimiter */
251 120 : int32_t read_y4m_frame_delimiter(EbConfig *cfg){
252 : unsigned char bufferY4Mheader[10];
253 : char *fresult;
254 :
255 120 : fresult = fgets((char *)bufferY4Mheader, sizeof(bufferY4Mheader), cfg->input_file);
256 :
257 120 : if(fresult == NULL){
258 0 : assert(feof(cfg->input_file));
259 0 : return EB_ErrorNone;
260 : }
261 :
262 120 : if (EB_STRCMP((const char*)bufferY4Mheader, "FRAME\n") != 0) {
263 0 : fprintf(cfg->error_log_file, "Failed to read proper y4m frame delimeter. Read broken.\n");
264 0 : return EB_ErrorBadParameter;
265 : }
266 :
267 120 : return EB_ErrorNone;
268 : }
269 :
270 : /* check if the input file is in YUV4MPEG2 (y4m) format */
271 2 : EbBool check_if_y4m(EbConfig *cfg)
272 : {
273 : size_t len;
274 : char buf[YUV4MPEG2_IND_SIZE+1];
275 2 : len = fread(buf, YUV4MPEG2_IND_SIZE, 1, cfg->input_file);
276 2 : if (len != 1)
277 0 : return EB_FALSE;
278 :
279 2 : if ((cfg->input_file != stdin) && (!cfg->input_file_is_fifo)) {
280 2 : fseek(cfg->input_file, 0, SEEK_SET);
281 : } else {
282 0 : memcpy(cfg->y4m_buf, buf, YUV4MPEG2_IND_SIZE);
283 : }
284 :
285 2 : buf[YUV4MPEG2_IND_SIZE] = 0;
286 2 : return (EB_STRCMP(buf, "YUV4MPEG2") == 0);
287 : }
|