1 /*****************************************************************************
2 * This file is part of Kvazaar HEVC encoder.
3 *
4 * Copyright (c) 2021, Tampere University, ITU/ISO/IEC, project contributors
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright notice, this
14 * list of conditions and the following disclaimer in the documentation and/or
15 * other materials provided with the distribution.
16 *
17 * * Neither the name of the Tampere University or ITU/ISO/IEC nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS
31 ****************************************************************************/
32
33 /*
34 * \file
35 */
36
37 #include <string.h>
38 #include <stdio.h>
39
40 #include "yuv_io.h"
41
fill_after_frame(unsigned height,unsigned array_width,unsigned array_height,kvz_pixel * data)42 static void fill_after_frame(unsigned height, unsigned array_width,
43 unsigned array_height, kvz_pixel *data)
44 {
45 kvz_pixel* p = data + height * array_width;
46 kvz_pixel* end = data + array_width * array_height;
47
48 while (p < end) {
49 // Fill the line by copying the line above.
50 memcpy(p, p - array_width, array_width);
51 p += array_width;
52 }
53 }
54
55
read_and_fill_frame_data(FILE * file,unsigned width,unsigned height,unsigned bytes_per_sample,unsigned array_width,kvz_pixel * data)56 static int read_and_fill_frame_data(FILE *file,
57 unsigned width, unsigned height, unsigned bytes_per_sample,
58 unsigned array_width, kvz_pixel *data)
59 {
60 kvz_pixel* p = data;
61 kvz_pixel* end = data + array_width * height;
62 kvz_pixel fill_char;
63 unsigned i;
64
65 while (p < end) {
66 // Read the beginning of the line from input.
67 if (width != fread(p, bytes_per_sample, width, file))
68 return 0;
69
70 // Fill the rest with the last pixel value.
71 fill_char = p[width - 1];
72
73 for (i = width; i < array_width; ++i) {
74 p[i] = fill_char;
75 }
76
77 p += array_width;
78 }
79 return 1;
80 }
81
82
swap_16b_buffer_bytes(kvz_pixel * input,int size)83 static void swap_16b_buffer_bytes(kvz_pixel* input, int size)
84 {
85 for (int i = 0; i < size; ++i) {
86 input[i] = ((input[i] & 0xff) << 8) + ((input[i] & 0xff00) >> 8);
87 }
88 }
89
90
shift_to_bitdepth(kvz_pixel * input,int size,int from_bitdepth,int to_bitdepth)91 static void shift_to_bitdepth(kvz_pixel* input, int size, int from_bitdepth, int to_bitdepth)
92 {
93 int shift = to_bitdepth - from_bitdepth;
94 kvz_pixel bitdepth_mask = (1 << from_bitdepth) - 1;
95
96 for (int i = 0; i < size; ++i) {
97 // Shifting by a negative number is undefined.
98 if (shift > 0) {
99 input[i] = (input[i] & bitdepth_mask) << shift;
100 } else {
101 input[i] = (input[i] & bitdepth_mask) >> shift;
102 }
103 }
104 }
105
106
107 // Shift and copy 1-byte aligned samples to 2-byte aligned array
shift_to_bitdepth_and_spread(kvz_pixel * input,int size,int from_bitdepth,int to_bitdepth)108 static void shift_to_bitdepth_and_spread(kvz_pixel *input,
109 int size,
110 int from_bitdepth,
111 int to_bitdepth)
112 {
113 assert(sizeof(kvz_pixel) > 1);
114 int shift = to_bitdepth - from_bitdepth;
115 unsigned char *byte_buf = (unsigned char *)input;
116 kvz_pixel bitdepth_mask = (1 << from_bitdepth) - 1;
117
118 // Starting from the back of the 1-byte samples, copy each sample to it's
119 // place in the 2-byte per sample array, overwriting the bytes that have
120 // already been copied in the process.
121 // Even though the two pointers are aliased, this should work because the
122 // future values read through byte_buf poiner never change as a result of
123 // writing through input pointer.
124 for (int i = size - 1; i >= 0; --i) {
125 // Shifting by a negative number is undefined.
126 if (shift > 0) {
127 input[i] = (byte_buf[i] & bitdepth_mask) << shift;
128 } else {
129 input[i] = (byte_buf[i] & bitdepth_mask) >> shift;
130 }
131 }
132 }
133
134
machine_is_big_endian()135 static bool machine_is_big_endian()
136 {
137 // Big and little endianess refers to which end of the egg you prefer to eat
138 // first. Therefore in big endian system, the most significant bits are in
139 // the first address.
140
141 uint16_t number = 1;
142 char first_byte = *(char*)&number;
143
144 return (first_byte == 0);
145 }
146
147
mask_to_bitdepth(kvz_pixel * buf,unsigned length,unsigned bitdepth)148 static void mask_to_bitdepth(kvz_pixel *buf, unsigned length, unsigned bitdepth)
149 {
150 kvz_pixel bitdepth_mask = (1 << bitdepth) - 1;
151 for (int i = 0; i < length; ++i) {
152 buf[i] = buf[i] & bitdepth_mask;
153 }
154 }
155
156
yuv_io_read_plane(FILE * file,unsigned in_width,unsigned in_height,unsigned in_bitdepth,unsigned out_width,unsigned out_height,unsigned out_bitdepth,kvz_pixel * out_buf)157 static int yuv_io_read_plane(
158 FILE* file,
159 unsigned in_width, unsigned in_height, unsigned in_bitdepth,
160 unsigned out_width, unsigned out_height, unsigned out_bitdepth,
161 kvz_pixel *out_buf)
162 {
163 unsigned bytes_per_sample = in_bitdepth > 8 ? 2 : 1;
164 unsigned buf_bytes = in_width * in_height * bytes_per_sample;
165 unsigned out_length = out_width * out_height;
166
167 if (in_width == out_width) {
168 // No need to extend pixels.
169 const size_t pixel_size = sizeof(unsigned char);
170 if (fread(out_buf, pixel_size, buf_bytes, file) != buf_bytes) return 0;
171 } else {
172 // Need to copy pixels to fill the image in horizontal direction.
173 if (!read_and_fill_frame_data(file, in_width, in_height, bytes_per_sample, out_width, out_buf)) return 0;
174 }
175
176 if (in_height != out_height) {
177 // Need to copy pixels to fill the image in vertical direction.
178 fill_after_frame(in_height, out_width, out_height, out_buf);
179 }
180
181 if (in_bitdepth > 8) {
182 // Assume little endian input.
183 if (machine_is_big_endian()) {
184 swap_16b_buffer_bytes(out_buf, out_length);
185 }
186 }
187
188 // Shift the data to the correct bitdepth.
189 // Ignore any bits larger than in_bitdepth to guarantee ouput data will be
190 // in the correct range.
191 if (in_bitdepth <= 8 && out_bitdepth > 8) {
192 shift_to_bitdepth_and_spread(out_buf, out_length, in_bitdepth, out_bitdepth);
193 } else if (in_bitdepth != out_bitdepth) {
194 shift_to_bitdepth(out_buf, out_length, in_bitdepth, out_bitdepth);
195 } else if (in_bitdepth % 8 != 0) {
196 mask_to_bitdepth(out_buf, out_length, out_bitdepth);
197 }
198
199 return 1;
200 }
201
202
read_frame_header(FILE * input)203 static int read_frame_header(FILE* input) {
204 char buffer[256];
205 bool frame_start = false;
206
207 while (!frame_start) {
208 for (int i = 0; i < 256; i++) {
209 buffer[i] = getc(input);
210 if (buffer[i] == EOF) return 0;
211 // ToDo: frame headers can have some information structured same as start headers
212 // This info is just skipped for now, since it's not clear what it could be.
213 if (buffer[i] == 0x0A) {
214 frame_start = true;
215 break;
216 }
217 }
218 }
219 return 1;
220 }
221
222 /**
223 * \brief Read a single frame from a file.
224 *
225 * Read luma and chroma values from file. Extend pixels if the image buffer
226 * is larger than the input image.
227 *
228 * \param file input file
229 * \param input_width width of the input video in pixels
230 * \param input_height height of the input video in pixels
231 * \param img_out image buffer
232 *
233 * \return 1 on success, 0 on failure
234 */
yuv_io_read(FILE * file,unsigned in_width,unsigned out_width,unsigned in_bitdepth,unsigned out_bitdepth,kvz_picture * img_out,unsigned file_format)235 int yuv_io_read(FILE* file,
236 unsigned in_width, unsigned out_width,
237 unsigned in_bitdepth, unsigned out_bitdepth,
238 kvz_picture *img_out, unsigned file_format)
239 {
240 assert(in_width % 2 == 0);
241 assert(out_width % 2 == 0);
242
243 int ok;
244
245 if (file_format == KVZ_FORMAT_Y4M) {
246 ok = read_frame_header(file);
247 if (!ok) return 0;
248 }
249
250
251
252 ok = yuv_io_read_plane(
253 file,
254 in_width, out_width, in_bitdepth,
255 img_out->width, img_out->height, out_bitdepth,
256 img_out->y);
257 if (!ok) return 0;
258
259 if (img_out->chroma_format != KVZ_CSP_400) {
260 unsigned uv_width_in = in_width / 2;
261 unsigned uv_height_in = out_width / 2;
262 unsigned uv_width_out = img_out->width / 2;
263 unsigned uv_height_out = img_out->height / 2;
264
265 ok = yuv_io_read_plane(
266 file,
267 uv_width_in, uv_height_in, in_bitdepth,
268 uv_width_out, uv_height_out, out_bitdepth,
269 img_out->u);
270 if (!ok) return 0;
271
272 ok = yuv_io_read_plane(
273 file,
274 uv_width_in, uv_height_in, in_bitdepth,
275 uv_width_out, uv_height_out, out_bitdepth,
276 img_out->v);
277 if (!ok) return 0;
278 }
279
280 return 1;
281 }
282
283
284 /**
285 * \brief Seek forward in a YUV file.
286 *
287 * \param file the input file
288 * \param frames number of frames to seek
289 * \param input_width width of the input video in pixels
290 * \param input_height height of the input video in pixels
291 *
292 * \return 1 on success, 0 on failure
293 */
yuv_io_seek(FILE * file,unsigned frames,unsigned input_width,unsigned input_height,unsigned file_format)294 int yuv_io_seek(FILE* file, unsigned frames,
295 unsigned input_width, unsigned input_height,
296 unsigned file_format)
297 {
298 const size_t frame_bytes = input_width * input_height * 3 / 2;
299
300 if (file_format == KVZ_FORMAT_Y4M) {
301 for (unsigned i = 0; i < frames; i++) {
302 if (!read_frame_header(file)) return 0;
303 if (fseek(file, frame_bytes, SEEK_CUR)) return 0;
304 }
305 return 1;
306 }
307
308 const int64_t skip_bytes = (int64_t)(frames * frame_bytes);
309
310 // Attempt to seek normally.
311 size_t error = fseek(file, skip_bytes, SEEK_CUR);
312 if (!error) return 1;
313
314 // Seek failed. Skip data by reading.
315 error = 0;
316 unsigned char* tmp[4096];
317 size_t bytes_left = skip_bytes;
318 while (bytes_left > 0 && !error) {
319 const size_t skip = MIN(4096, bytes_left);
320 error = fread(tmp, sizeof(unsigned char), skip, file) != skip;
321 bytes_left -= skip;
322 }
323
324 return !error || feof(file);
325 }
326
327
328 /**
329 * \brief Write a single frame to a file.
330 *
331 * \param file output file
332 * \param img image to output
333 * \param output_width width of the output in pixels
334 * \param output_height height of the output in pixels
335 *
336 * \return 1 on success, 0 on failure
337 */
yuv_io_write(FILE * file,const kvz_picture * img,unsigned output_width,unsigned output_height)338 int yuv_io_write(FILE* file,
339 const kvz_picture *img,
340 unsigned output_width, unsigned output_height)
341 {
342 const int width = img->width;
343 for (int y = 0; y < output_height; ++y) {
344 fwrite(&img->y[y * width], sizeof(*img->y), output_width, file);
345 // TODO: Check that fwrite succeeded.
346 }
347
348 if (img->chroma_format != KVZ_CSP_400) {
349 for (int y = 0; y < output_height / 2; ++y) {
350 fwrite(&img->u[y * width / 2], sizeof(*img->u), output_width / 2, file);
351 }
352 for (int y = 0; y < output_height / 2; ++y) {
353 fwrite(&img->v[y * width / 2], sizeof(*img->v), output_width / 2, file);
354 }
355 }
356
357 return 1;
358 }
359