source: trunk/src/testing/app/bitplay/img2bmv.c @ 4

Revision 4, 14.8 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1/******************************************************************************
2 * SAGE - Scalable Adaptive Graphics Environment
3 *
4 * Copyright (C) 2004 Electronic Visualization Laboratory,
5 * University of Illinois at Chicago
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above
15 *    copyright notice, this list of conditions and the following disclaimer
16 *    in the documentation and/or other materials provided with the distribution.
17 *  * Neither the name of the University of Illinois at Chicago nor
18 *    the names of its contributors may be used to endorse or promote
19 *    products derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
34 *
35 *****************************************************************************/
36
37#define _LARGEFILE64_SOURCE 1
38#define _FILE_OFFSET_BITS   64
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <errno.h>
45#include <string.h>
46
47#ifndef sun
48#include <endian.h>
49#endif
50
51#include "bpmovie.h"
52#include "imginfo.h"
53
54    /* Macros for (A<<24) + (B<<16) + (G<<8) + R-format pixels as from getimgdata */
55
56#if defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
57# define ROFF   3
58# define GOFF   2
59# define BOFF   1
60#else   /* assume little-endian */
61# define ROFF   0
62# define GOFF   1
63# define BOFF   2
64#endif
65
66#define PR(p)  (p)[ROFF]
67#define PG(p)  (p)[GOFF]
68#define PB(p)  (p)[BOFF]
69
70char Usage[] = "\
71Usage: %s -o OUTFILE.bmv  [-w XSIZExYSIZE] [-e OFFSET[m|k|f]@OUTDISK] [-p BPP] [-f rate] FROM-TO%%INCR LEFTPATTERN [RIGHTPATTERN]\n\
72Encode a sequence of TIFF/SGI/JPEG/etc. files as a .bmv movie,\n\
73optionally storing the image data in a separate file or disk partition.\n\
74Options:\n\
75    -o outfile.bmv      Write movie (or its header at least) to this file.  Required.\n\
76    -e offset[m|k|f]@outdisk   If given, store the movie data at the given\n\
77                        offset on the given device or file.  THe offset may be\n\
78                        specified as a number with suffix 'm', 'k' or 'f'\n\
79                        in which case it's in units of 2^20 (MB), 2^10 (KB),\n\
80                        or the frame size, respectively.\n\
81    -p bytesperpixel\n\
82        Selects pixel format:  1: grayscale  2: 16-bit 5-6-5 RGB  3: 24-bit RGB\n\
83    -f rate             preferred frame rate (if any), frames/sec\n\
84\n\
85    from-to%%incr       range of frame numbers to apply to left+righpattern\n\
86    leftpattern         printf format string for image name, e.g. /some/where/left.%%04d.tif\n\
87    rightpattern        similar for right-hand stereo image, or \"-\" to omit\n";
88
89
90char *prog;
91
92static int bytesper[5] = { 0, 1, 2, 3, 4 };     /* indexed by enum pixeltype values */
93
94int skipmissing = 1;
95int prefrate = 0;
96
97#define MAXALIGN        16384   /* largest credible page size */
98
99/* Find head with both hands -- compute tile arrangement */
100void findhead( bpmvhead_t *head, int xwin, int ywin, int xtile, int ytile, enum pixeltype format )
101{
102    head->magic = BPMV3_MAGIC;
103    head->xsize = xwin;
104    head->ysize = ywin;
105    head->format = format;
106    head->xtile = xtile;
107    head->ytile = ytile;
108    head->nxtile = (xwin + xtile - 1) / xtile;
109    head->nytile = (ywin + ytile - 1) / ytile;
110
111    /* Configure for fully packed tiles, which should be most
112     * efficient for stuffing at graphics card
113     */
114
115    head->tilerowstride = bytesper[format] * xtile;
116    head->xtilestride = head->tilerowstride * ytile;
117    head->ytilestride = head->xtilestride * head->nxtile;
118    head->imagestride = (head->ytilestride * head->nytile + MAXALIGN-1) & ~(MAXALIGN-1);
119
120    head->start = head->imagestride;
121}
122
123int writeheader( char *outfname, off_t foffset, bpmvhead_t *head )
124{
125    int outfd;
126
127    outfd = outfname == NULL ? 1 : open(outfname, O_LARGEFILE|O_CREAT|O_TRUNC|O_WRONLY, 0666);
128
129    if(outfd < 0) {
130        fprintf(stderr, "%s: Can't create output: %s: %s\n",
131                prog, outfname, strerror(errno));
132        exit(1);
133    }
134
135    if(head->extfname[0] == '\0') {
136        /* All in one file. */
137        char *headbuf = (char *)malloc( head->start );
138
139        memset(headbuf, 0, head->start);
140        memcpy( headbuf, head, sizeof(*head) );
141        if(write( outfd, headbuf, head->start ) != head->start) {
142            fprintf(stderr, "%s: %s: can't write %lld-byte header: %s\n",
143                    prog, outfname, head->start, strerror(errno));
144            exit(1);
145        }
146        free(headbuf);
147        return outfd;
148
149    } else {
150        int headsize = &head->cmd[ strlen(head->cmd) + 1 ] - (char *)head;
151        if(write( outfd, head, headsize ) != headsize) {
152            fprintf(stderr, "%s: %s: can't write %d-byte header: %s\n",
153                    prog, outfname, headsize, strerror(errno));
154            exit(1);
155        }
156
157        close(outfd);
158
159        outfd = open( head->extfname, O_LARGEFILE|O_CREAT|O_WRONLY, 0666 );
160        if(outfd < 0) {
161            fprintf(stderr, "%s: %s: Can't open external-data file for writing: %s\n",
162                    prog, head->extfname, strerror(errno));
163            exit(1);
164        }
165
166        if(lseek(outfd, head->start, SEEK_SET) < 0) {
167            fprintf(stderr, "%s: %s: Can't seek to %lld on external-data file: %s\n",
168                    prog, head->extfname, (long long) head->start, strerror(errno));
169            exit(1);
170        }
171
172        return outfd;
173    }
174}
175
176
177
178unsigned char dither3[8][8];    /* dither bias values as function of position mod 8 */
179
180/* 3-bit (0..7) dither pattern */
181static void initdither3( unsigned char dith3[8][8] )
182{
183    int i, j;
184
185    for(i = 0; i < 8; i++) {
186        for(j = 0; j < 8; j++) {
187            int ij = i^j;
188
189            /* Discard bottom 3 bits of 6-bit dither pattern */
190            dith3[i][j] =
191                ( ((ij&4)<<3) | ((i&4)<<2) | ((ij&2)<<2) | ((i&2)<<1) | ((ij&1)<<1) | (i&1)
192                ) >> 3;
193        }
194    }
195}
196
197static void encode( unsigned char *aus, bpmvhead_t *head,
198                int aox0, int xwin, int ywin,
199                unsigned char *data, struct imginfo *info )
200{
201    int xtile = head->xtile;
202    int ytile = head->ytile;
203    int xtilestride = head->xtilestride;
204    int ytilestride = head->ytilestride;
205    int tilerowstride = head->tilerowstride;
206    enum pixeltype format = head->format;
207    int obpp = bytesper[ format ];
208
209    int inx, iny;               /* size of intersection between image and output */
210    int ix0, iy0;               /* initial position within image */
211    int irowstride;             /* row-stride in image */
212    int tox0, tox1, toy0, toy1; /* range of tiles in image-output intersection */
213    int tox, toy;               /* current tile number */
214    unsigned int ox0, oy0;
215
216#define IBPP    4               /* bytes per input-image pixel, as provided by getimgdata() */
217
218
219    irowstride = IBPP * info->xsize; /* getimgdata() was told to make 4-byte-per-pixel format */
220
221    /* How does image fit within [xwin,ywin]? */
222    if(info->xsize <= xwin) {
223        /* Just right or too small.  Center image in output area */
224        ix0 = 0;
225        inx = info->xsize;
226        ox0 = aox0 + (xwin - info->xsize) / 2;
227    } else {
228        /* Too large.  Center and crop image to fit. */
229        ix0 = (info->xsize - xwin) / 2;
230        inx = xwin;
231        ox0 = aox0;
232    }
233    if(info->ysize <= ywin) {
234        /* Just right or too small.  Center image in output area */
235        iy0 = 0;
236        iny = info->ysize;
237        oy0 = (ywin - info->ysize) / 2;
238    } else {
239        /* Too large.  Center and crop image to fit. */
240        iy0 = (info->ysize - ywin) / 2;
241        iny = ywin;
242        oy0 = 0;
243    }
244
245    tox0 = ox0 / xtile;   tox1 = (ox0 + inx-1) / xtile;
246    toy0 = oy0 / ytile;   toy1 = (oy0 + iny-1) / ytile;
247
248    /* Loop over tiles */
249    for(toy = toy0; toy <= toy1; toy++) {
250        int iytile = iy0 + ytile*(toy-toy0);
251        int oytend = (iny - iytile >= ytile) ? ytile : iny - iytile;
252        int oxstart = ox0 % xtile;
253
254        for(tox = tox0; tox <= tox1; tox++, oxstart = 0) {
255            /* Loop within this tile */
256            int ixtile = ix0 + xtile*(tox-tox0);
257            int oxtend = (inx - ixtile >= xtile) ? xtile : inx - ixtile;
258            unsigned char *ipstart = data + IBPP * ixtile + irowstride * iytile;
259            unsigned char *opstart = aus
260                        + toy * ytilestride
261                        + tox * xtilestride
262                        + oxstart * obpp;
263            int oxt, oyt;
264
265            for(oyt = 0; oyt < oytend; oyt++) {
266                unsigned char *ip = ipstart + oyt * irowstride;
267                unsigned char *op = opstart + oyt * tilerowstride;
268                switch( format ) {
269
270                    case GRAY8:
271                        /* Convert RGB to grayscale using NTSC weighting convention */
272                        for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op++)
273                            *op = (77*PR(ip) + 151*PG(ip) + 28*PB(ip)) >> 8;
274                        break;
275
276                    case RGB565:
277                      {
278                        unsigned char *dith3row = &dither3[oyt & 7][0];
279                        for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 2) {
280                            /* Apply ordered dither while packing into 5-6-5 format */
281                            unsigned short r, g, b;
282                            unsigned char dith3 = dith3row[oxt & 7] >> 3;
283                            r = PR(ip) + dith3;       if(r > 255) r = 255;
284                            g = PG(ip) + (dith3>>1);  if(g > 255) g = 255;
285                            b = PB(ip) + dith3;       if(b > 255) b = 255;
286                            *(unsigned short *)op =
287                                ((r & 0xF8) << 8) |
288                                ((g & 0xFC) << 3) |
289                                ((b >> 3) & 0x1F);
290                        }
291                        break;
292                      }
293
294                    case RGB888:
295                        for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 3) {
296                            op[0] = PR(ip);
297                            op[1] = PG(ip);
298                            op[2] = PB(ip);
299                        }
300                        break;
301
302                    case ABGR8888:
303                        for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 4) {
304                            op[0] = 255;
305                            op[1] = PB(ip);
306                            op[2] = PG(ip);
307                            op[3] = PR(ip);
308                        }
309                        break;
310                }
311            }
312        }
313    }
314}
315
316int main( int argc, char *argv[] )
317{
318    char *outname = NULL;
319    char *extout = NULL;
320    long long outoffset = 0;
321    int offsetframes = 0;
322
323    char *left, *right;
324    int ffrom, fto, finc, frameno;
325    int i, count;
326
327    enum pixeltype pixelformat = RGB565;
328    int xwin = 1920, ywin = 1080;
329    int xtile = 512, ytile = 512;
330    bpmvhead_t head;
331    int outfd = -1;
332    int relshift = 0;
333
334    unsigned char *aus;
335
336    memset( &head, 0, sizeof(head));
337
338    for(i = 0, count = 0; i < argc; i++) {
339        int len = strlen(argv[i]);
340        if(count + len > sizeof(head.cmd)-2)
341            len = sizeof(head.cmd)-2 - count;
342        memcpy(head.cmd+count, argv[i], len);
343        count += len;
344        head.cmd[count++] = ' ';
345    }
346    head.cmd[--count] = '\0';
347
348    prog = argv[0];
349
350    while(argc>2 && argv[1][0] == '-' && argv[1][1] != '\0') {
351        switch(argv[1][1]) {
352        case 'o':
353            outname = argv[2];
354            argc -= 2, argv += 2;
355            break;
356
357        case 'f':       /* preferred play rate */
358            prefrate = atoi(argv[2]);
359            if(strchr(argv[2], 'm') != NULL)
360                prefrate = -abs(prefrate);      /* in ms/frame rather than frames/sec */
361            argc -= 2, argv += 2;
362            break;
363
364        case 'e': {
365            char *cp = strchr(argv[2], '@');
366            if(cp) {
367                char *ep;
368                outoffset = strtoll(argv[2], &ep, 0);
369                switch(*ep) {
370                case 'k': case 'K': outoffset <<= 10; break;
371                case 'm': case 'M': outoffset <<= 20; break;
372                case 'f': case 'F': offsetframes = 1; break;
373                }
374                extout = cp+1;
375            } else {
376                extout = argv[2];
377            }
378            argc -= 2, argv += 2;
379          }
380          break;
381
382        case 'L':
383          relshift = -atoi(argv[2]);  argc -= 2, argv += 2;
384          break;
385
386        case 'R':
387          relshift = atoi(argv[2]);  argc -= 2, argv += 2;
388          break;
389
390        case 'p':
391          pixelformat = (enum pixeltype) atoi(argv[2]);
392          if(pixelformat < 1 || pixelformat > 4) {
393              fprintf(stderr, "%s -p: expected pixel format 1 (gray), 2 (rgr565), 3 (rgb24), 4 (rgba), not %s\n", prog, argv[2]);
394              exit(1);
395          }
396          argc -= 2, argv += 2;
397          break;
398
399        case 'w':
400          sscanf(argv[2], "%d%*c%d", &xwin, &ywin);
401          argc -= 2, argv += 2;
402          break;
403
404        default:
405          argc = 0;
406        }
407    }
408
409    if(argc < 3) {
410        fprintf(stderr, Usage, prog);
411        exit(1);
412    }
413
414    ffrom = 0;
415    fto = -1;
416    finc = 1;
417
418    if(sscanf(argv[1], "%d-%d%%%d", &ffrom, &fto, &finc) <= 0) {
419        fprintf(stderr, "%s: expected from-to%%incr, got %s\n", prog, argv[1]);
420        exit(1);
421    }
422
423    left = argv[2];
424    right = argc>3 ? argv[3] : NULL;
425
426    if(fto < 0)
427        fto = ffrom;
428    if(finc == 0)
429        finc = 1;
430
431    count = (fto - ffrom) / finc + 1;
432
433    findhead( &head, right ? 2*xwin : xwin, ywin, xtile, ytile, pixelformat );
434
435
436    head.nframes = count;
437
438    if(relshift != 0) {
439        head.prefshift = relshift;
440        head.flags |= BPF_PREFSHIFT;
441    }
442
443    if(prefrate != 0) {
444        head.prefrate = prefrate;
445        head.flags |= BPF_PREFRATE;
446    }
447
448    if(right != NULL)
449        head.flags |= BPF_STEREO;
450
451    if(extout != NULL) {
452        if(offsetframes)
453            outoffset *= head.imagestride;
454        head.flags |= BPF_EXTDATA;
455        head.start = outoffset;
456        strncpy( head.extfname, extout, sizeof(head.extfname)-1 );
457    }
458
459    aus = (unsigned char *) malloc( head.imagestride );
460    if(aus == NULL) {
461        fprintf(stderr, "%s: Can't allocate %d bytes for image buffer\n",
462                prog, head.imagestride);
463        exit(1);
464    }
465    memset(aus, 0, head.imagestride);
466
467    if(pixelformat == RGB565)
468        initdither3( dither3 );
469
470    fprintf(stderr, "RIGHT [%s], XWIN %d YWIN %d XTILE %d YTILE %d\n", right, xwin, ywin, xtile, ytile);
471
472    for(frameno = ffrom, i = 0; i < count; i++, frameno += finc) {
473        struct imginfo lefti, righti;
474        unsigned char *leftd = NULL, *rightd = NULL;
475        char leftname[300], rightname[300];
476
477        /* Find names of images for this frame */
478        sprintf(leftname, left, frameno);
479
480        /* Read images.  Give up if left-hand is missing. */
481        leftd = getimgdata( leftname, NULL, &lefti, 1, 4, 1 );
482        if(leftd == NULL) {
483            fprintf(stderr, "%s: can't open %s\n", prog, leftname);
484            if(skipmissing)
485                continue;
486            else
487                break;
488        }
489
490        /* Is this first time?  Emit header if so. */
491
492        if(i == 0) {
493            outfd = writeheader( outname, outoffset, &head );
494        }
495
496        /* Re-encode left (or only) image into buffer */
497
498        encode( aus, &head, 0,    xwin, ywin,  leftd, &lefti   );
499
500        if(right != NULL) {
501            /* If there's a right-hand image, encode it too. */
502            sprintf(rightname, right, frameno);
503            rightd = (0==strcmp(rightname, "-")) ? NULL
504                    : getimgdata( rightname, NULL, &righti, 1, 4, 1 );
505            if(rightd == NULL) {
506                if(rightname[0] != '-')
507                    fprintf(stderr, "%s: can't open %s\n", prog, rightname);
508                rightd = leftd;
509                righti = lefti;
510            }
511
512            encode( aus, &head, xwin, xwin, ywin, rightd, &righti );
513        }
514
515        /* DEBUG */
516        *(int *)( aus + head.imagestride-4 ) = frameno;
517
518        errno = 0;
519        if(write( outfd, aus, head.imagestride ) != head.imagestride ) {
520            fprintf(stderr, "%s: %s: write error: %s\n",
521                    prog, outname ? outname : "stdout", strerror(errno));
522            exit(1);
523        }
524        free(leftd);
525        if(rightd != leftd && rightd != NULL)
526            free(rightd);
527    }
528    return 0;
529}
Note: See TracBrowser for help on using the repository browser.