1 /*
2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3 * All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the copyright owner, nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #ifndef _OAPV_APP_Y4M_H_
32 #define _OAPV_APP_Y4M_H_
33
34 typedef struct y4m_params {
35 int w;
36 int h;
37 int fps_num;
38 int fps_den;
39 int color_format;
40 int bit_depth;
41 } y4m_params_t;
42
y4m_test(FILE * fp)43 static int y4m_test(FILE *fp)
44 {
45
46 char buffer[9] = { 0 };
47
48 /*Peek to check if y4m header is present*/
49 if(!fread(buffer, 1, 8, fp))
50 return -1;
51 fseek(fp, 0, SEEK_SET);
52 buffer[8] = '\0';
53 if(memcmp(buffer, "YUV4MPEG", 8)) {
54 return 0;
55 }
56 return 1;
57 }
58
y4m_parse_tags(y4m_params_t * y4m,char * tags)59 static int y4m_parse_tags(y4m_params_t *y4m, char *tags)
60 {
61
62 char *p;
63 char *q;
64 char t_buff[20];
65 int found_w = 0, found_h = 0, found_cf = 0;
66 int fps_n, fps_d, pix_ratio_n, pix_ratio_d;
67
68 for(p = tags;; p = q) {
69
70 /*Skip any leading spaces.*/
71 while(*p == ' ')
72 p++;
73
74 /*If that's all we have, stop.*/
75 if(p[0] == '\0')
76 break;
77
78 /*Find the end of this tag.*/
79 for(q = p + 1; *q != '\0' && *q != ' '; q++) {
80 }
81
82 /*Process the tag.*/
83 switch(p[0]) {
84 case 'W': {
85 if(sscanf(p + 1, "%d", &y4m->w) != 1)
86 return OAPV_ERR;
87 found_w = 1;
88 break;
89 }
90 case 'H': {
91 if(sscanf(p + 1, "%d", &y4m->h) != 1)
92 return OAPV_ERR;
93 found_h = 1;
94 break;
95 }
96 case 'F': {
97 if(sscanf(p + 1, "%d:%d", &fps_n, &fps_d) != 2)
98 return OAPV_ERR;
99 y4m->fps_num = fps_n;
100 y4m->fps_den = fps_d;
101 break;
102 }
103 case 'I': {
104 // interlace = p[1];
105 break;
106 }
107 case 'A': {
108 if(sscanf(p + 1, "%d:%d", &pix_ratio_n, &pix_ratio_d) != 2)
109 return OAPV_ERR;
110 break;
111 }
112 case 'C': {
113 if(q - p > 16)
114 return OAPV_ERR;
115 memcpy(t_buff, p + 1, q - p - 1);
116 t_buff[q - p - 1] = '\0';
117 found_cf = 1;
118 break;
119 }
120 /*Ignore unknown tags.*/
121 }
122 }
123
124 if(!(found_w == 1 && found_h == 1)) {
125 logerr("Mandatory arugments are not found in y4m header");
126 return OAPV_ERR;
127 }
128 /* Setting default colorspace to yuv420 and input_bd to 8 if header info. is NA */
129 if(!found_cf) {
130 y4m->color_format = OAPV_CF_YCBCR420;
131 y4m->bit_depth = 8;
132 }
133
134 if(strcmp(t_buff, "420jpeg") == 0 || strcmp(t_buff, "420") == 0 ||
135 strcmp(t_buff, "420mpeg2") == 0 || strcmp(t_buff, "420paidv") == 0) {
136 y4m->color_format = OAPV_CF_YCBCR420;
137 y4m->bit_depth = 8;
138 }
139 else if(strcmp(t_buff, "422") == 0) {
140 y4m->color_format = OAPV_CF_YCBCR422;
141 y4m->bit_depth = 8;
142 }
143 else if(strcmp(t_buff, "444") == 0) {
144 y4m->color_format = OAPV_CF_YCBCR444;
145 y4m->bit_depth = 8;
146 }
147 else if(strcmp(t_buff, "420p10") == 0) {
148 y4m->color_format = OAPV_CF_YCBCR420;
149 y4m->bit_depth = 10;
150 }
151 else if(strcmp(t_buff, "422p10") == 0) {
152 y4m->color_format = OAPV_CF_YCBCR422;
153 y4m->bit_depth = 10;
154 }
155 else if(strcmp(t_buff, "444p10") == 0) {
156 y4m->color_format = OAPV_CF_YCBCR444;
157 y4m->bit_depth = 10;
158 }
159 else if(strcmp(t_buff, "mono") == 0) {
160 y4m->color_format = OAPV_CF_YCBCR400;
161 y4m->bit_depth = 8;
162 }
163 else {
164 y4m->color_format = OAPV_CF_UNKNOWN;
165 y4m->bit_depth = -1;
166 }
167 return OAPV_OK;
168 }
169
y4m_header_parser(FILE * ip_y4m,y4m_params_t * y4m)170 int y4m_header_parser(FILE *ip_y4m, y4m_params_t *y4m)
171 {
172 const int head_size = 128;
173 char buffer[128];
174 int ret;
175 int i;
176
177 memset(buffer, 0, sizeof(char) * head_size);
178
179 /*Read until newline, or 128 cols, whichever happens first.*/
180 for(i = 0; i < (head_size - 1); i++) {
181
182 if(!fread(buffer + i, 1, 1, ip_y4m))
183 return -1;
184 if(buffer[i] == '\n')
185 break;
186 }
187 /*We skipped too much header data.*/
188 if(i == (head_size - 1)) {
189 logerr("Error parsing header; not a YUV2MPEG2 file?\n");
190 return -1;
191 }
192 buffer[i] = '\0';
193 if(memcmp(buffer, "YUV4MPEG", 8)) {
194 logerr("Incomplete magic for YUV4MPEG file.\n");
195 return -1;
196 }
197 if(buffer[8] != '2') {
198 logerr("Incorrect YUV input file version; YUV4MPEG2 required.\n");
199 }
200 ret = y4m_parse_tags(y4m, buffer + 5);
201 if(ret < 0) {
202 logerr("Error parsing YUV4MPEG2 header.\n");
203 return ret;
204 }
205 return 0;
206 }
207
y4m_update_param(args_parser_t * args,y4m_params_t * y4m)208 static void y4m_update_param(args_parser_t *args, y4m_params_t *y4m)
209 {
210 args->set_int(args, "width", y4m->w);
211 args->set_int(args, "height", y4m->h);
212 char tmp_fps[256];
213 sprintf(tmp_fps, "%d/%d", y4m->fps_num, y4m->fps_den);
214 args->set_str(args, "fps", tmp_fps);
215 args->set_int(args, "input-depth", y4m->bit_depth);
216 }
217
write_y4m_header(char * fname,oapv_imgb_t * imgb)218 static int write_y4m_header(char *fname, oapv_imgb_t *imgb)
219 {
220 int color_format = OAPV_CS_GET_FORMAT(imgb->cs);
221 int bit_depth = OAPV_CS_GET_BIT_DEPTH(imgb->cs);
222 int len = 80;
223 int buff_len = 0;
224 char buf[80] = {
225 '\0',
226 };
227 char c_buf[16] = {
228 '\0',
229 };
230 FILE *fp;
231
232 if(color_format == OAPV_CF_YCBCR420) {
233 if(bit_depth == 8)
234 strcpy(c_buf, "420mpeg2");
235 else if(bit_depth == 10)
236 strcpy(c_buf, "420p10");
237 }
238 else if(color_format == OAPV_CF_YCBCR422) {
239 if(bit_depth == 8)
240 strcpy(c_buf, "422");
241 else if(bit_depth == 10)
242 strcpy(c_buf, "422p10");
243 }
244 else if(color_format == OAPV_CF_YCBCR444) {
245 if(bit_depth == 8)
246 strcpy(c_buf, "444");
247 else if(bit_depth == 10)
248 strcpy(c_buf, "444p10");
249 }
250 else if(color_format == OAPV_CF_YCBCR400) {
251 if(bit_depth == 8)
252 strcpy(c_buf, "mono");
253 }
254
255 if(strlen(c_buf) == 0) {
256 logerr("Color format is not suuported by y4m");
257 return -1;
258 }
259
260 /*setting fps to 30 by default as there is no fps related parameter */
261 buff_len = snprintf(buf, len, "YUV4MPEG2 W%d H%d F%d:%d Ip C%s\n",
262 imgb->w[0], imgb->h[0], 30, 1, c_buf);
263
264 fp = fopen(fname, "ab");
265 if(fp == NULL) {
266 logerr("cannot open file = %s\n", fname);
267 return -1;
268 }
269 if(buff_len != fwrite(buf, 1, buff_len, fp)) {
270 fclose(fp);
271 return -1;
272 }
273 fclose(fp);
274 return 0;
275 }
276 /* Frame level header or separator */
write_y4m_frame_header(char * fname)277 static int write_y4m_frame_header(char *fname)
278 {
279 FILE *fp;
280 fp = fopen(fname, "ab");
281 if(fp == NULL) {
282 logerr("cannot open file = %s\n", fname);
283 return -1;
284 }
285 if(6 != fwrite("FRAME\n", 1, 6, fp)) {
286 fclose(fp);
287 return -1;
288 }
289 fclose(fp);
290 return 0;
291 }
292
293 #endif /* _OAPV_APP_Y4M_H_ */