12 uint32_t f_framedata[];
16 static voidpf
internal_alloc(voidpf opaque
, uInt items
, uInt size
)
18 size_t _items
= items
;
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
);
27 if(!(ret
= calloc(items
, size
))) {
28 fprintf(stderr
, "internal_alloc: Can't allocate %zu bytes.\n",
35 static void internal_free(voidpf opaque
, voidpf 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
);
48 if(w
== 0 || h
== 0) {
49 fprintf(stderr
, "frame_create: Width and height must be positive.\n");
53 struct frame
* f
= malloc(size
);
55 fprintf(stderr
, "Can't allocate %zu bytes for frame.\n", size
);
64 void frame_release(struct frame
* frame
)
69 #define INPUTBUFSZ 1024
71 struct frame_input_stream
75 uint64_t fis_current_seq
;
78 uint8_t fis_buffer
[INPUTBUFSZ
];
81 struct frame_output_stream
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
));
93 fprintf(stderr
, "fis_open: Can't allocate %zu bytes for input stream.\n",
94 sizeof(struct frame_input_stream
));
97 fis
->fis_filp
= fopen(filename
, "rb");
99 fprintf(stderr
, "fis_open: Can't open input file %s.\n", filename
);
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
);
107 fprintf(stderr
, "fis_open: Can't initialize zlib: %s\n", fis
->fis_zlib
.msg
);
110 fis
->fis_new_flag
= 1;
111 fis
->fis_eof_flag
= 0;
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
);
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
);
132 fprintf(stderr
, "reinitialize_inflate: Can't initialize zlib: %s\n", fis
->fis_zlib
.msg
);
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
);
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");
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
;
173 fprintf(stderr
, "read_inflate: Unexpected end of input file.\n");
177 fis
->fis_new_flag
= 0;
182 static void decode_pixeldata(uint32_t* pixels
, uint8_t* data
, size_t count
)
184 for(size_t i
= 0; i
< count
; i
++) {
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
++) {
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
;
217 r
= read_inflate(fis
, frameheaders
, 4);
219 return NULL
; /* End of stream. */
221 fprintf(stderr
, "fis_next_frame: Unexpected end of input.\n");
224 if(frameheaders
[0] == 255 && frameheaders
[1] == 255 && frameheaders
[3] == 255 && frameheaders
[4] == 255) {
225 timeseq
+= 0xFFFFFFFFUL
;
228 r
= read_inflate(fis
, frameheaders
+ 4, 4);
230 fprintf(stderr
, "fis_next_frame: Unexpected end of input.\n");
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");
252 decode_pixeldata(f
->f_framedata
+ pixelptr
, blockbuffer
, BLOCKBUF_PIXELS
);
253 pixelptr
+= BLOCKBUF_PIXELS
;
254 pixelsleft
-= BLOCKBUF_PIXELS
;
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");
262 decode_pixeldata(f
->f_framedata
+ pixelptr
, blockbuffer
, pixelsleft
);
263 pixelptr
+= pixelsleft
;
267 fis
->fis_current_seq
= f
->f_timeseq
;
271 void fis_close(struct frame_input_stream
* fis
)
273 inflateEnd(&fis
->fis_zlib
);
274 fclose(fis
->fis_filp
);
278 struct frame_output_stream
* fos_open(const char* filename
)
280 struct frame_output_stream
* fos
= malloc(sizeof(struct frame_output_stream
));
282 fprintf(stderr
, "fos_open: Can't allocate %zu bytes for output stream.\n",
283 sizeof(struct frame_output_stream
));
286 fos
->fos_filp
= fopen(filename
, "wb");
288 fprintf(stderr
, "fos_open: Can't open output file %s.\n", filename
);
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
);
297 fprintf(stderr
, "fos_open: Can't initialize zlib: %s\n", fos
->fos_zlib
.msg
);
300 fos
->fos_zlib
.avail_out
= INPUTBUFSZ
;
301 fos
->fos_zlib
.next_out
= fos
->fos_buffer
;
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
);
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");
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
) {
333 fos
->fos_zlib
.next_in
= (Bytef
*)tmp
;
334 fos
->fos_zlib
.avail_in
= 4;
335 fos
->fos_current_seq
+= 0xFFFFFFFFU
;
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
;
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;
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
;
364 encodepixels(tmp
, f
->f_framedata
+ pixelptr
, pixelsleft
);
365 pixelptr
+= pixelsleft
;
366 fos
->fos_zlib
.avail_in
= 4 * pixelsleft
;
369 fos
->fos_zlib
.next_in
= (Bytef
*)tmp
;
372 int r
= deflate(&fos
->fos_zlib
, 0);
374 fprintf(stderr
, "fos_save_frame: Can't compress data: %s\n", fos
->fos_zlib
.msg
);
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");
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
);
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");
402 fos
->fos_zlib
.avail_out
= INPUTBUFSZ
;
403 fos
->fos_zlib
.next_out
= fos
->fos_buffer
;
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
);