Add SoundCard and FMCard to documentation
[jpcrr.git] / streamtools / frame.c
blob39c0906afd2f0f3a9b2ae071d32b13bca963b94d
1 #include "frame.h"
2 #include <zlib.h>
3 #include <stdio.h>
4 #include <stdlib.h>
6 /*
7 struct frame
9 uint64_t f_timeseq;
10 uint32_t f_width;
11 uint32_t f_height;
12 uint32_t f_framedata[];
16 static voidpf internal_alloc(voidpf opaque, uInt items, uInt size)
18 size_t _items = items;
19 size_t _size = size;
20 voidpf ret;
22 if((_items * _size) / _size != _items) {
23 fprintf(stderr, "internal_alloc: %lu*%lu bytes overflows VM space.\n",
24 (unsigned long)items, (unsigned long)size);
25 exit(1);
27 if(!(ret = calloc(items, size))) {
28 fprintf(stderr, "internal_alloc: Can't allocate %zu bytes.\n",
29 _items * _size);
30 exit(1);
32 return ret;
35 static void internal_free(voidpf opaque, voidpf address)
37 free(address);
40 struct frame* frame_create(uint32_t w, uint32_t h)
42 size_t size = (size_t)w * (size_t)h * sizeof(uint32_t) + sizeof(struct frame);
43 if((size - sizeof(struct frame)) / h / sizeof(uint32_t) != w) {
44 fprintf(stderr, "frame_create: %lu*%lu pixel image overflows VM space.\n",
45 (unsigned long)w, (unsigned long)h);
46 exit(1);
48 if(w == 0 || h == 0) {
49 fprintf(stderr, "frame_create: Width and height must be positive.\n");
50 exit(1);
53 struct frame* f = malloc(size);
54 if(!f) {
55 fprintf(stderr, "Can't allocate %zu bytes for frame.\n", size);
56 exit(1);
58 f->f_timeseq = 0;
59 f->f_width = w;
60 f->f_height = h;
61 return f;
64 void frame_release(struct frame* frame)
66 free(frame);
69 #define INPUTBUFSZ 1024
71 struct frame_input_stream
73 FILE* fis_filp;
74 z_stream fis_zlib;
75 uint64_t fis_current_seq;
76 int fis_new_flag;
77 int fis_eof_flag;
78 uint8_t fis_buffer[INPUTBUFSZ];
81 struct frame_output_stream
83 FILE* fos_filp;
84 z_stream fos_zlib;
85 uint64_t fos_current_seq;
86 uint8_t fos_buffer[INPUTBUFSZ];
89 struct frame_input_stream* fis_open(const char* filename)
91 struct frame_input_stream* fis = malloc(sizeof(struct frame_input_stream));
92 if(!fis) {
93 fprintf(stderr, "fis_open: Can't allocate %zu bytes for input stream.\n",
94 sizeof(struct frame_input_stream));
95 exit(1);
97 fis->fis_filp = fopen(filename, "rb");
98 if(!fis->fis_filp) {
99 fprintf(stderr, "fis_open: Can't open input file %s.\n", filename);
100 exit(1);
102 fis->fis_zlib.zalloc = internal_alloc;
103 fis->fis_zlib.zfree = internal_free;
104 fis->fis_zlib.opaque = NULL;
105 int r = inflateInit(&fis->fis_zlib);
106 if(r != Z_OK) {
107 fprintf(stderr, "fis_open: Can't initialize zlib: %s\n", fis->fis_zlib.msg);
108 exit(1);
110 fis->fis_new_flag = 1;
111 fis->fis_eof_flag = 0;
112 return fis;
115 static void reinitialize_inflate(struct frame_input_stream* fis)
117 z_stream* zlib = &fis->fis_zlib;
119 Bytef* nin = zlib->next_in;
120 Bytef* nout = zlib->next_out;
121 uInt ain = zlib->avail_in;
122 uInt aout = zlib->avail_out;
123 if(inflateEnd(zlib) != Z_OK) {
124 fprintf(stderr, "reinitialize_inflate: Can't finalize zlib: %s\n", zlib->msg);
125 exit(1);
127 fis->fis_zlib.zalloc = internal_alloc;
128 fis->fis_zlib.zfree = internal_free;
129 fis->fis_zlib.opaque = NULL;
130 int r = inflateInit(&fis->fis_zlib);
131 if(r != Z_OK) {
132 fprintf(stderr, "reinitialize_inflate: Can't initialize zlib: %s\n", fis->fis_zlib.msg);
133 exit(1);
135 zlib->next_in = nin;
136 zlib->next_out = nout;
137 zlib->avail_in = ain;
138 zlib->avail_out = aout;
141 static size_t read_inflate(struct frame_input_stream* fis, uint8_t* buf, size_t toread)
143 fis->fis_zlib.next_out = (Bytef*)buf;
144 fis->fis_zlib.avail_out = (uInt)toread;
146 while(fis->fis_zlib.avail_out > 0) {
147 int r = inflate(&fis->fis_zlib, 0);
148 if(r == Z_STREAM_END) {
149 /* This is special. We got to renitialize the stream. */
150 reinitialize_inflate(fis);
151 fis->fis_new_flag = 1;
152 } else if(r != Z_OK && r != Z_BUF_ERROR) {
153 fprintf(stderr, "read_inflate: Can't uncompress data: %s\n", fis->fis_zlib.msg);
154 exit(1);
156 if(fis->fis_zlib.avail_in == 0 && !fis->fis_eof_flag) {
157 /* Refill the buffer. */
158 fis->fis_zlib.next_in = (Bytef*)fis->fis_buffer;
159 fis->fis_zlib.avail_in = (uInt)fread(fis->fis_buffer, 1, INPUTBUFSZ, fis->fis_filp);
160 if(ferror(fis->fis_filp)) {
161 fprintf(stderr, "read_inflate: Input file read error.\n");
162 exit(1);
164 if(feof(fis->fis_filp)) {
165 fis->fis_eof_flag = 1;
166 if(fis->fis_new_flag)
167 return toread - fis->fis_zlib.avail_out;
169 } else if(fis->fis_zlib.avail_in == 0) {
170 if(fis->fis_new_flag)
171 return toread - fis->fis_zlib.avail_out;
172 else {
173 fprintf(stderr, "read_inflate: Unexpected end of input file.\n");
174 exit(1);
177 fis->fis_new_flag = 0;
179 return toread;
182 static void decode_pixeldata(uint32_t* pixels, uint8_t* data, size_t count)
184 for(size_t i = 0; i < count; i++) {
185 pixels[i] = 0;
186 pixels[i] += ((uint32_t)data[4 * i + 1] << 16);
187 pixels[i] += ((uint32_t)data[4 * i + 2] << 8);
188 pixels[i] += ((uint32_t)data[4 * i + 3]);
192 static void encodepixels(uint8_t* targ, uint32_t* pixels, size_t count)
194 for(size_t i = 0; i < count; i++) {
195 targ[4 * i] = 0;
196 targ[4 * i + 1] = (uint8_t)(pixels[i] >> 16);
197 targ[4 * i + 2] = (uint8_t)(pixels[i] >> 8);
198 targ[4 * i + 3] = (uint8_t)(pixels[i]);
202 #define BLOCKBUF_PIXELS 1024
203 #define BYTES_PER_PIXEL 4
205 struct frame* fis_next_frame(struct frame_input_stream* fis)
207 uint8_t frameheaders[8];
208 uint8_t blockbuffer[BYTES_PER_PIXEL * BLOCKBUF_PIXELS];
209 uint64_t timeseq = fis->fis_current_seq;
210 uint32_t width = 0;
211 uint32_t height = 0;
212 size_t pixelsleft;
213 size_t pixelptr = 0;
214 size_t r;
216 back:
217 r = read_inflate(fis, frameheaders, 4);
218 if(r == 0)
219 return NULL; /* End of stream. */
220 if(r < 4) {
221 fprintf(stderr, "fis_next_frame: Unexpected end of input.\n");
222 exit(1);
224 if(frameheaders[0] == 255 && frameheaders[1] == 255 && frameheaders[3] == 255 && frameheaders[4] == 255) {
225 timeseq += 0xFFFFFFFFUL;
226 goto back;
228 r = read_inflate(fis, frameheaders + 4, 4);
229 if(r < 4) {
230 fprintf(stderr, "fis_next_frame: Unexpected end of input.\n");
231 exit(1);
234 timeseq += ((uint32_t)frameheaders[0] << 24);
235 timeseq += ((uint32_t)frameheaders[1] << 16);
236 timeseq += ((uint32_t)frameheaders[2] << 8);
237 timeseq += ((uint32_t)frameheaders[3]);
238 width += ((uint32_t)frameheaders[4] << 8);
239 width += ((uint32_t)frameheaders[5]);
240 height += ((uint32_t)frameheaders[6] << 8);
241 height += ((uint32_t)frameheaders[7]);
242 pixelsleft = width * height;
243 struct frame* f = frame_create(width, height);
244 f->f_timeseq = timeseq;
246 while(pixelsleft > 0) {
247 if(pixelsleft > BLOCKBUF_PIXELS) {
248 if(read_inflate(fis, blockbuffer, sizeof(blockbuffer)) < sizeof(blockbuffer)) {
249 fprintf(stderr, "fis_next_frame: Unexpected end of input.\n");
250 exit(1);
252 decode_pixeldata(f->f_framedata + pixelptr, blockbuffer, BLOCKBUF_PIXELS);
253 pixelptr += BLOCKBUF_PIXELS;
254 pixelsleft -= BLOCKBUF_PIXELS;
255 } else {
256 if(read_inflate(fis, blockbuffer, BYTES_PER_PIXEL * pixelsleft) <
257 BYTES_PER_PIXEL * pixelsleft) {
259 fprintf(stderr, "fis_next_frame: Unexpected end of input.\n");
260 exit(1);
262 decode_pixeldata(f->f_framedata + pixelptr, blockbuffer, pixelsleft);
263 pixelptr += pixelsleft;
264 pixelsleft = 0;
267 fis->fis_current_seq = f->f_timeseq;
268 return f;
271 void fis_close(struct frame_input_stream* fis)
273 inflateEnd(&fis->fis_zlib);
274 fclose(fis->fis_filp);
275 free(fis);
278 struct frame_output_stream* fos_open(const char* filename)
280 struct frame_output_stream* fos = malloc(sizeof(struct frame_output_stream));
281 if(!fos) {
282 fprintf(stderr, "fos_open: Can't allocate %zu bytes for output stream.\n",
283 sizeof(struct frame_output_stream));
284 exit(1);
286 fos->fos_filp = fopen(filename, "wb");
287 if(!fos->fos_filp) {
288 fprintf(stderr, "fos_open: Can't open output file %s.\n", filename);
289 exit(1);
291 fos->fos_zlib.zalloc = internal_alloc;
292 fos->fos_zlib.zfree = internal_free;
293 fos->fos_zlib.opaque = NULL;
294 fos->fos_current_seq = 0;
295 int r = deflateInit(&fos->fos_zlib, Z_BEST_COMPRESSION);
296 if(r != Z_OK) {
297 fprintf(stderr, "fos_open: Can't initialize zlib: %s\n", fos->fos_zlib.msg);
298 exit(1);
300 fos->fos_zlib.avail_out = INPUTBUFSZ;
301 fos->fos_zlib.next_out = fos->fos_buffer;
302 return fos;
304 void fos_save_frame(struct frame_output_stream* fos, struct frame* frame)
306 if(frame->f_timeseq < fos->fos_current_seq) {
307 fprintf(stderr, "fos_save_frame: Timecodes jump backwards: %llu < %llu.\n",
308 frame->f_timeseq, fos->fos_current_seq);
309 exit(1);
311 int time_saved = 0;
312 int header_saved = 0;
313 uint8_t tmp[INPUTBUFSZ];
314 struct frame* f = frame;
315 uint32_t pixelsleft = f->f_width * f->f_height;
316 uint32_t pixelptr = 0;
318 while(pixelsleft > 0 || fos->fos_zlib.avail_in > 0 || !header_saved) {
319 if(fos->fos_zlib.avail_out == 0) {
320 if(fwrite(fos->fos_buffer, 1, INPUTBUFSZ, fos->fos_filp) < INPUTBUFSZ) {
321 fprintf(stderr, "fos_close: Error flushing output stream.\n");
322 exit(1);
324 fos->fos_zlib.next_out = (Bytef*)fos->fos_buffer;
325 fos->fos_zlib.avail_out = (uInt)INPUTBUFSZ;
327 if(fos->fos_zlib.avail_in > 0) {
328 } else if(frame->f_timeseq - fos->fos_current_seq >= 0xFFFFFFFFU) {
329 tmp[0] = 255;
330 tmp[1] = 255;
331 tmp[2] = 255;
332 tmp[3] = 255;
333 fos->fos_zlib.next_in = (Bytef*)tmp;
334 fos->fos_zlib.avail_in = 4;
335 fos->fos_current_seq += 0xFFFFFFFFU;
336 continue;
337 } else if(!time_saved) {
338 uint64_t diff = frame->f_timeseq - fos->fos_current_seq;
339 tmp[0] = (uint8_t)(diff >> 24);
340 tmp[1] = (uint8_t)(diff >> 16);
341 tmp[2] = (uint8_t)(diff >> 8);
342 tmp[3] = (uint8_t)(diff);
343 fos->fos_zlib.next_in = (Bytef*)tmp;
344 fos->fos_zlib.avail_in = 4;
345 fos->fos_current_seq = frame->f_timeseq;
346 time_saved = 1;
347 continue;
348 } else if(!header_saved) {
349 tmp[0] = (uint8_t)(f->f_width >> 8);
350 tmp[1] = (uint8_t)(f->f_width);
351 tmp[2] = (uint8_t)(f->f_height >> 8);
352 tmp[3] = (uint8_t)(f->f_height);
353 fos->fos_zlib.next_in = (Bytef*)tmp;
354 fos->fos_zlib.avail_in = 4;
355 header_saved = 1;
356 continue;
357 } else {
358 if(pixelsleft > INPUTBUFSZ / BYTES_PER_PIXEL) {
359 encodepixels(tmp, f->f_framedata + pixelptr, INPUTBUFSZ / BYTES_PER_PIXEL);
360 pixelptr += INPUTBUFSZ / BYTES_PER_PIXEL;
361 pixelsleft -= INPUTBUFSZ / BYTES_PER_PIXEL;
362 fos->fos_zlib.avail_in = INPUTBUFSZ;
363 } else {
364 encodepixels(tmp, f->f_framedata + pixelptr, pixelsleft);
365 pixelptr += pixelsleft;
366 fos->fos_zlib.avail_in = 4 * pixelsleft;
367 pixelsleft = 0;
369 fos->fos_zlib.next_in = (Bytef*)tmp;
370 continue;
372 int r = deflate(&fos->fos_zlib, 0);
373 if(r != Z_OK) {
374 fprintf(stderr, "fos_save_frame: Can't compress data: %s\n", fos->fos_zlib.msg);
375 exit(1);
379 if(fos->fos_zlib.avail_out < INPUTBUFSZ) {
380 if(fwrite(fos->fos_buffer, 1, INPUTBUFSZ - fos->fos_zlib.avail_out, fos->fos_filp) < INPUTBUFSZ -
381 fos->fos_zlib.avail_out) {
383 fprintf(stderr, "fos_save_frame: Error flushing tail of frame.\n");
384 exit(1);
386 fos->fos_zlib.avail_out = INPUTBUFSZ;
387 fos->fos_zlib.next_out = fos->fos_buffer;
392 void fos_close(struct frame_output_stream* fos)
394 int r = deflate(&fos->fos_zlib, Z_FINISH);
395 do {
396 if(fwrite(fos->fos_buffer, 1, INPUTBUFSZ - fos->fos_zlib.avail_out, fos->fos_filp) < INPUTBUFSZ -
397 fos->fos_zlib.avail_out) {
399 fprintf(stderr, "fos_save_frame: Error flushing tail of stream.\n");
400 exit(1);
402 fos->fos_zlib.avail_out = INPUTBUFSZ;
403 fos->fos_zlib.next_out = fos->fos_buffer;
405 if(r == Z_OK)
406 r = deflate(&fos->fos_zlib, Z_FINISH);
407 } while(r == Z_OK || fos->fos_zlib.avail_out < INPUTBUFSZ);
408 if(r != Z_STREAM_END)
409 fprintf(stderr, "Error flushing tail\n");
411 deflateEnd(&fos->fos_zlib);
412 fclose(fos->fos_filp);
413 free(fos);