Skip to content

Commit a2b0105

Browse files
committed
PAM/Y4M utils: move implementation to .c file
1 parent 2078743 commit a2b0105

File tree

5 files changed

+418
-340
lines changed

5 files changed

+418
-340
lines changed

Makefile.in

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,16 @@ COMMON_OBJS = \
170170
src/utils/jpeg_reader.o \
171171
src/utils/list.o \
172172
src/utils/misc.o \
173-
src/utils/string_view_utils.o \
174173
src/utils/nat.o \
175174
src/utils/net.o \
176175
src/utils/packet_counter.o \
176+
src/utils/pam.o \
177177
src/utils/parallel_conv.o \
178+
src/utils/profile_timer.o \
178179
src/utils/resource_manager.o \
179180
src/utils/ring_buffer.o \
180181
src/utils/sdp.o \
182+
src/utils/string_view_utils.o \
181183
src/utils/synchronized_queue.o \
182184
src/utils/text.o \
183185
src/utils/thread.o \
@@ -187,7 +189,7 @@ COMMON_OBJS = \
187189
src/utils/video_pattern_generator.o \
188190
src/utils/wait_obj.o \
189191
src/utils/worker.o \
190-
src/utils/profile_timer.o \
192+
src/utils/y4m.o \
191193
src/video.o \
192194
src/video_frame.o \
193195
src/video_codec.o \

src/utils/pam.c

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/**
2+
* @file utils/pam.c
3+
* @author Martin Pulec <[email protected]>
4+
*
5+
* Very simple library to read and write PAM/PPM files. Only binary formats
6+
* (P5, P6) for PNM are processed, P4 is also not used.
7+
*
8+
* This file is part of GPUJPEG.
9+
*/
10+
/*
11+
* Copyright (c) 2013-2022, CESNET z.s.p.o.
12+
*
13+
* All rights reserved.
14+
*
15+
* Redistribution and use in source and binary forms, with or without
16+
* modification, are permitted provided that the following conditions are met:
17+
*
18+
* * Redistributions of source code must retain the above copyright
19+
* notice, this list of conditions and the following disclaimer.
20+
*
21+
* * Redistributions in binary form must reproduce the above copyright
22+
* notice, this list of conditions and the following disclaimer in the
23+
* documentation and/or other materials provided with the distribution.
24+
*
25+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35+
* POSSIBILITY OF SUCH DAMAGE.
36+
*/
37+
38+
#include <ctype.h>
39+
#include <errno.h>
40+
#include <stdio.h>
41+
#include <stdlib.h>
42+
#include <string.h>
43+
44+
#include "pam.h"
45+
46+
static void parse_pam(FILE *file, struct pam_metadata *info) {
47+
char line[128];
48+
fgets(line, sizeof line - 1, file);
49+
while (!feof(file) && !ferror(file)) {
50+
if (strcmp(line, "ENDHDR\n") == 0) {
51+
break;
52+
}
53+
char *spc = strchr(line, ' ');
54+
if (spc == NULL) {
55+
break;
56+
}
57+
const char *key = line;
58+
*spc = '\0';
59+
const char *val = spc + 1;
60+
if (strcmp(key, "WIDTH") == 0) {
61+
info->width = atoi(val);
62+
} else if (strcmp(key, "HEIGHT") == 0) {
63+
info->height = atoi(val);
64+
} else if (strcmp(key, "DEPTH") == 0) {
65+
info->depth = atoi(val);
66+
} else if (strcmp(key, "MAXVAL") == 0) {
67+
info->maxval = atoi(val);
68+
} else if (strcmp(key, "TUPLTYPE") == 0) {
69+
// ignored - assuming MAXVAL == 255, value of DEPTH is sufficient
70+
// to determine pixel format
71+
} else {
72+
fprintf(stderr, "unrecognized key %s in PAM header\n", key);
73+
}
74+
fgets(line, sizeof line - 1, file);
75+
}
76+
}
77+
78+
static bool parse_pnm(FILE *file, char pnm_id, struct pam_metadata *info) {
79+
switch (pnm_id) {
80+
case '1':
81+
case '2':
82+
case '3':
83+
case '4':
84+
fprintf(stderr, "Unsupported PNM P%c\n", pnm_id);
85+
return false;
86+
case '5':
87+
info->depth = 1;
88+
break;
89+
case '6':
90+
info->depth = 3;
91+
break;
92+
default:
93+
fprintf(stderr, "Wrong PNM P%c\n", pnm_id);
94+
return false;
95+
}
96+
int item_nr = 0;
97+
while (!feof(file) && !ferror(file)) {
98+
int val = 0;
99+
if (fscanf(file, "%d", &val) == 1) {
100+
switch (item_nr++) {
101+
case 0:
102+
info->width = val;
103+
break;
104+
case 1:
105+
info->height = val;
106+
break;
107+
case 2:
108+
info->maxval = val;
109+
getc(file); // skip whitespace following header
110+
return true;
111+
}
112+
} else {
113+
if (getc(file) == '#') {
114+
int ch;
115+
while ((ch = getc(file)) != '\n' && ch != EOF)
116+
;
117+
} else {
118+
break;
119+
}
120+
}
121+
}
122+
fprintf(stderr, "Problem parsing PNM header, number of hdr items successfully read: %d\n", item_nr);
123+
return false;
124+
}
125+
126+
bool pam_read(const char *filename, struct pam_metadata *info, unsigned char **data, void *(*allocator)(size_t)) {
127+
char line[128];
128+
errno = 0;
129+
FILE *file = fopen(filename, "rb");
130+
if (!file) {
131+
fprintf(stderr, "Failed to open %s: %s", filename, strerror(errno));
132+
return false;
133+
}
134+
memset(info, 0, sizeof *info);
135+
fgets(line, 4, file);
136+
if (feof(file) || ferror(file)) {
137+
fprintf(stderr, "File '%s' read error: %s\n", filename, strerror(errno));
138+
}
139+
if (strcmp(line, "P7\n") == 0) {
140+
parse_pam(file, info);
141+
} else if (strlen(line) == 3 && line[0] == 'P' && isspace(line[2])) {
142+
parse_pnm(file, line[1], info);
143+
} else {
144+
fprintf(stderr, "File '%s' doesn't seem to be valid PAM or PNM.\n", filename);
145+
fclose(file);
146+
return false;
147+
}
148+
if (info->width * info->height == 0) {
149+
fprintf(stderr, "Unspecified size header field!");
150+
fclose(file);
151+
return false;
152+
}
153+
if (info->depth == 0) {
154+
fprintf(stderr, "Unspecified depth header field!");
155+
fclose(file);
156+
return false;
157+
}
158+
if (info->maxval == 0) {
159+
fprintf(stderr, "Unspecified maximal value field!");
160+
fclose(file);
161+
return false;
162+
}
163+
if (data == NULL || allocator == NULL) {
164+
fclose(file);
165+
return true;
166+
}
167+
size_t datalen = (size_t) info->depth * info->width * info->height * (info->maxval <= 255 ? 1 : 2);
168+
*data = (unsigned char *) allocator(datalen);
169+
if (!*data) {
170+
fprintf(stderr, "Unspecified depth header field!");
171+
fclose(file);
172+
return false;
173+
}
174+
fread((char *) *data, datalen, 1, file);
175+
if (feof(file) || ferror(file)) {
176+
perror("Unable to load PAM/PNM data from file");
177+
fclose(file);
178+
return false;
179+
}
180+
fclose(file);
181+
return true;
182+
}
183+
184+
bool pam_write(const char *filename, unsigned int width, unsigned int height, int depth, int maxval, const unsigned char *data, bool pnm) {
185+
errno = 0;
186+
FILE *file = fopen(filename, "wb");
187+
if (!file) {
188+
fprintf(stderr, "Failed to open %s for writing: %s", filename, strerror(errno));
189+
return false;
190+
}
191+
if (pnm) {
192+
if (depth != 1 && depth != 3) {
193+
fprintf(stderr, "Only 1 or 3 channels supported for PNM!\n");
194+
return false;
195+
}
196+
fprintf(file, "P%d\n"
197+
"%u %u\n"
198+
"%d\n",
199+
depth == 1 ? 5 : 6,
200+
width, height, maxval);
201+
} else {
202+
const char *tuple_type = "INVALID";
203+
switch (depth) {
204+
case 4: tuple_type = "RGB_ALPHA"; break;
205+
case 3: tuple_type = "RGB"; break;
206+
case 2: tuple_type = "GRAYSCALE_ALPHA"; break;
207+
case 1: tuple_type = "GRAYSCALE"; break;
208+
default: fprintf(stderr, "Wrong depth: %d\n", depth);
209+
}
210+
fprintf(file, "P7\n"
211+
"WIDTH %u\n"
212+
"HEIGHT %u\n"
213+
"DEPTH %d\n"
214+
"MAXVAL %d\n"
215+
"TUPLTYPE %s\n"
216+
"ENDHDR\n",
217+
width, height, depth, maxval, tuple_type);
218+
}
219+
fwrite((const char *) data, width * height * depth, maxval <= 255 ? 1 : 2, file);
220+
bool ret = !ferror(file);
221+
if (!ret) {
222+
perror("Unable to write PAM/PNM data");
223+
}
224+
fclose(file);
225+
return ret;
226+
}
227+

0 commit comments

Comments
 (0)