blind-apply-kernel.c - blind - suckless command-line video editing utility
 (HTM) git clone git://git.suckless.org/blind
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       blind-apply-kernel.c (3898B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #ifndef TYPE
            3 #include "common.h"
            4 
            5 USAGE("[-apPxy] kernel-stream")
            6 
            7 static int no_alpha = 0;
            8 static int dont_premultiply = 0;
            9 static int per_pixel = 0;
           10 static int wrap_x = 0;
           11 static int wrap_y = 0;
           12 static size_t kern_w;
           13 static size_t kern_h;
           14 
           15 #define FILE "blind-apply-kernel.c"
           16 #include "define-functions.h"
           17 
           18 int
           19 main(int argc, char *argv[])
           20 {
           21         struct stream colour, kernel;
           22         void (*process)(struct stream *colour, struct stream *kernel);
           23         size_t tmp;
           24 
           25         ARGBEGIN {
           26         case 'a':
           27                 no_alpha = 1;
           28                 break;
           29         case 'p':
           30                 per_pixel = 1;
           31                 break;
           32         case 'P':
           33                 dont_premultiply = 1;
           34                 break;
           35         case 'x':
           36                 wrap_x = 1;
           37                 break;
           38         case 'y':
           39                 wrap_y = 1;
           40                 break;
           41         default:
           42                 usage();
           43         } ARGEND;
           44 
           45         if (argc != 1)
           46                 usage();
           47 
           48         eopen_stream(&colour, NULL);
           49         eopen_stream(&kernel, argv[0]);
           50 
           51         SELECT_PROCESS_FUNCTION(&colour);
           52         CHECK_ALPHA_CHAN(&colour);
           53         CHECK_N_CHAN(&colour, 4, 4);
           54         if (colour.encoding != kernel.encoding || colour.n_chan != kernel.n_chan)
           55                 eprintf("videos use incompatible pixel formats");
           56         if (per_pixel && !(kernel.width % colour.width || kernel.height % colour.height))
           57                 eprintf("-p is specified but the dimensions of kernel-stream "
           58                         "are not multiples of the dimensions of stdin.");
           59 
           60         kern_w = per_pixel ? kernel.width  / colour.width  : kernel.width;
           61         kern_h = per_pixel ? kernel.height / colour.height : kernel.height;
           62 
           63         tmp = kernel.height, kernel.height = kern_h;
           64         echeck_dimensions(&colour, WIDTH | HEIGHT, NULL);
           65         echeck_dimensions(&kernel, WIDTH | HEIGHT, NULL);
           66         kernel.height = tmp;
           67 
           68         fprint_stream_head(stdout, &colour);
           69         efflush(stdout, "<stdout>");
           70         process(&colour, &kernel);
           71         return 0;
           72 }
           73 
           74 #else
           75 
           76 static void
           77 PROCESS(struct stream *colour, struct stream *kernel)
           78 {
           79         TYPE *out, *clr, *krn, *kern, *pix;
           80         size_t i, x, y, n, x2, y2;
           81         ssize_t cx, cy, xoff, yoff;
           82 
           83         out = emalloc(colour->frame_size);
           84         clr = emalloc(colour->frame_size);
           85         krn = emalloc2(kern_h, kernel->row_size);
           86 
           87         xoff = (ssize_t)(kern_w / 2);
           88         yoff = (ssize_t)(kern_h / 2);
           89 
           90         n = colour->width * colour->height * colour->n_chan;
           91         while (eread_frame(colour, clr)) {
           92                 /* premultiply */
           93                 if (!no_alpha && !dont_premultiply) {
           94                         for (i = 0; i < n; i += 4) {
           95                                 clr[i + 0] *= clr[i + 3];
           96                                 clr[i + 1] *= clr[i + 3];
           97                                 clr[i + 2] *= clr[i + 3];
           98                         }
           99                 }
          100 
          101                 /* apply kernel */
          102                 memset(out, 0, colour->frame_size);
          103                 pix = out;
          104                 for (y = 0; y < colour->height; y++) {
          105                         if ((!y || per_pixel) && !eread_segment(kernel, krn, kern_h * kernel->row_size))
          106                                 goto done;
          107                         for (x = 0; x < colour->width; x++, pix += colour->n_chan) {
          108                                 kern = per_pixel ? (krn + x * kern_w * kernel->n_chan) : krn;
          109                                 for (y2 = 0; y2 < kern_h; y2++, kern += kernel->width * kernel->n_chan) {
          110                                         cy = (ssize_t)(y + y2) - yoff;
          111                                         if (cy < 0 || (size_t)cy >= colour->height) {
          112                                                 if (!wrap_y)
          113                                                         continue;
          114                                                 cy %= (ssize_t)(colour->height);
          115                                                 if (cy < 0)
          116                                                         cy += (ssize_t)(colour->height);
          117                                         }
          118                                         for (x2 = 0; x2 < kern_w; x2++) {
          119                                                 cx = (ssize_t)(x + x2) - xoff;
          120                                                 if (cx < 0 || (size_t)cx >= colour->width) {
          121                                                         if (!wrap_x)
          122                                                                 continue;
          123                                                         cx %= (ssize_t)(colour->width);
          124                                                         if (cx < 0)
          125                                                                 cx += (ssize_t)(colour->width);
          126                                                 }
          127                                                 for (i = 0; i < colour->n_chan; i++)
          128                                                         pix[i] += kern[x2 * kernel->n_chan + i] *
          129                                                                   clr[((size_t)cy * colour->width + (size_t)cx) * colour->n_chan + i];
          130                                         }
          131                                 }
          132                         }
          133                 }
          134 
          135                 /* unpremultiply */
          136                 if (!dont_premultiply) {
          137                         for (i = 0; i < n; i += 4) {
          138                                 if (out[i + 3]) {
          139                                         out[i + 0] /= out[i + 3];
          140                                         out[i + 1] /= out[i + 3];
          141                                         out[i + 2] /= out[i + 3];
          142                                 }
          143                         }
          144                 }
          145 
          146                 /* ensure video is opaque if -a was used */
          147                 if (no_alpha)
          148                         for (i = 0; i < n; i += 4)
          149                                 out[i + 3] = 1;
          150 
          151                 /* output video */
          152                 ewriteall(STDOUT_FILENO, out, colour->frame_size, "<stdout>");
          153         }
          154 done:
          155 
          156         free(out);
          157         free(clr);
          158         free(krn);
          159 }
          160 
          161 #endif