|
| 1 | +// fhwrap: Unpack a farbherd stream into a farbfeld stream, pipe it to a binary, repack. |
| 2 | +// |
| 3 | +// License: |
| 4 | +// farbherd - animation format & tools, designed to be similar to farbfeld. |
| 5 | +// Written in 2018 by 20kdc <[email protected]>, vifino <[email protected]> and contributors. |
| 6 | +// |
| 7 | +// To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. |
| 8 | +// This software is distributed without any warranty. |
| 9 | +// You should have received a copy of the CC0 Public Domain Dedication along with this software. |
| 10 | +// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. |
| 11 | + |
| 12 | +#include <stdio.h> |
| 13 | +#include <stdlib.h> |
| 14 | +#include <string.h> |
| 15 | +#include <sys/types.h> |
| 16 | +#include <unistd.h> |
| 17 | +#include <sys/wait.h> |
| 18 | +#include <err.h> |
| 19 | + |
| 20 | +#include "farbherd.h" |
| 21 | + |
| 22 | +void run_worker(uint16_t *input, uint16_t *output, size_t bufsz, farbfeld_header_t head, int argc, char* argv[]) { |
| 23 | + int infd[2]; |
| 24 | + if (pipe(infd) == -1) { |
| 25 | + fprintf(stderr, "Failed to create input pipe.\n"); |
| 26 | + _exit(1); |
| 27 | + } |
| 28 | + |
| 29 | + pid_t writer = fork(); |
| 30 | + if (writer == 0) { |
| 31 | + // writer child. |
| 32 | + FILE* f = fdopen(infd[1], "w"); |
| 33 | + if (!f) |
| 34 | + err(2, "Failed to open pipe"); |
| 35 | + farbherd_write_farbfeld_header(f, head); |
| 36 | + fwrite(input, bufsz, 1, f); |
| 37 | + fclose(f); |
| 38 | + _exit(0); |
| 39 | + } |
| 40 | + // parent |
| 41 | + close(infd[1]); // child took care of it. |
| 42 | + |
| 43 | + int outfd[2]; |
| 44 | + if (pipe(outfd) == -1) { |
| 45 | + fprintf(stderr, "Failed to create output pipe.\n"); |
| 46 | + _exit(1); |
| 47 | + } |
| 48 | + |
| 49 | + int exit; |
| 50 | + pid_t filter = fork(); |
| 51 | + if (filter == 0) { |
| 52 | + // child. |
| 53 | + close(outfd[0]); // close reading end of output |
| 54 | + |
| 55 | + dup2(infd[0], 0); // get stdin from parent |
| 56 | + dup2(outfd[1], 1); // write to parent |
| 57 | + |
| 58 | + // no longer needed |
| 59 | + close(infd[0]); |
| 60 | + close(outfd[1]); |
| 61 | + |
| 62 | + // Do the thing. |
| 63 | + if(execvp(argv[0], argv)) |
| 64 | + err(1, "Failed to execute child"); |
| 65 | + } |
| 66 | + |
| 67 | + // parent. |
| 68 | + close(infd[0]); // close reading end of input |
| 69 | + close(outfd[1]); // close writing end of output |
| 70 | + |
| 71 | + FILE* f = fdopen(outfd[0], "r"); |
| 72 | + if (!f) |
| 73 | + err(2, "Failed to open pipe"); |
| 74 | + |
| 75 | + farbfeld_header_t rhead; |
| 76 | + if (farbherd_read_farbfeld_header(f, &rhead)) { |
| 77 | + fprintf(stderr, "Failed to read worker farbfeld header.\n"); |
| 78 | + _exit(1); |
| 79 | + } |
| 80 | + if ((rhead.width != head.width) || (rhead.height != rhead.height)) { |
| 81 | + fprintf(stderr, "Worker returned wrong farbfeld canvas size?\n"); |
| 82 | + _exit(1); |
| 83 | + } |
| 84 | + if (farbherd_read_buffer(f, output, bufsz)) { |
| 85 | + fprintf(stderr, "Worker failed to write frame?\n"); |
| 86 | + _exit(1); |
| 87 | + } |
| 88 | + |
| 89 | + int status = 0; |
| 90 | + pid_t wpid; |
| 91 | + int workers = 2; |
| 92 | + while (workers) { |
| 93 | + wpid = wait(&status); |
| 94 | + if (!wpid) |
| 95 | + err(2, "Wait error"); |
| 96 | + workers--; |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +int main(int argc, char ** argv) { |
| 101 | + if ((argc < 2)) { |
| 102 | + fprintf(stderr, "Usage: %s [cmd..]\n", argv[0]); |
| 103 | + return 1; |
| 104 | + } |
| 105 | + |
| 106 | + farbherd_header_t head; |
| 107 | + if (farbherd_read_farbherd_header(stdin, &head)) { |
| 108 | + fputs("Failed to read farbherd header\n", stderr); |
| 109 | + return 1; |
| 110 | + } |
| 111 | + farbherd_write_farbherd_header(stdout, head); |
| 112 | + fflush(stdout); |
| 113 | + |
| 114 | + size_t datasize = farbherd_datasize(head.imageHead); |
| 115 | + fprintf(stderr, "%i x %i @ %i / %i\n", head.imageHead.width, head.imageHead.height, head.frameTimeMul, head.frameTimeDiv); |
| 116 | + uint16_t* work_in = 0; |
| 117 | + uint16_t* work_out = 0; |
| 118 | + uint16_t* outbuf = 0; |
| 119 | + if (datasize) { |
| 120 | + work_in = calloc(1, datasize); |
| 121 | + work_out = calloc(1, datasize); |
| 122 | + if (!work_in && !work_out) { |
| 123 | + fputs("Failed to allocate workspace memory\n", stderr); |
| 124 | + return 1; |
| 125 | + } |
| 126 | + outbuf = malloc(datasize); |
| 127 | + if (!outbuf) { |
| 128 | + fputs("Failed to allocate workspace memory\n", stderr); |
| 129 | + return 1; |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + farbherd_frame_t inputframe; |
| 134 | + if (farbherd_init_farbherd_frame(&inputframe, head)) { |
| 135 | + fputs("Failed to allocate incoming frame memory\n", stderr); |
| 136 | + return 1; |
| 137 | + } |
| 138 | + |
| 139 | + while (1) { |
| 140 | + // Read farbherd frame. |
| 141 | + if (farbherd_read_farbherd_frame(stdin, &inputframe, head)) |
| 142 | + return 0; |
| 143 | + farbherd_apply_delta(work_in, inputframe.deltas, datasize); |
| 144 | + |
| 145 | + // Run the buffer through the worker filter. |
| 146 | + run_worker(inputframe.deltas, outbuf, datasize, head.imageHead, argc, argv + 1); |
| 147 | + |
| 148 | + // Write out the completed frame. |
| 149 | + farbherd_calc_apply_delta(work_out, outbuf, datasize); |
| 150 | + fwrite(outbuf, datasize, 1, stdout); |
| 151 | + fflush(stdout); |
| 152 | + } |
| 153 | + return 0; |
| 154 | +} |
0 commit comments