xref: /aosp_15_r20/external/libopenapv/app/oapv_app_y4m.h (revision abb65b4b03b69e1d508d4d9a44dcf199df16e7c3)
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_ */