Blame converter/ppm/eyuvtoppm.c

Packit 78deda
/* Bryan got this from mm.ftp-cs.berkeley.edu from the package
Packit 78deda
   mpeg-encode-1.5b-src under the name eyuvtoppm.c on March 30, 2000.  
Packit 78deda
   The file was dated April 14, 1995.  
Packit 78deda
Packit 78deda
   Bryan rewrote the program entirely to match Netpbm coding style,
Packit 78deda
   use the Netpbm libraries and also to output to stdout and ignore
Packit 78deda
   any specification of an output file on the command line and not
Packit 78deda
   segfault when called with no arguments.
Packit 78deda
Packit 78deda
   There was no attached documentation except for this:  Encoder/Berkeley
Packit 78deda
   YUV format is merely the concatenation of Y, U, and V data in order.
Packit 78deda
   Compare with Abekda YUV, which interlaces Y, U, and V data.  */
Packit 78deda
Packit 78deda
/*
Packit 78deda
 * Copyright (c) 1995 The Regents of the University of California.
Packit 78deda
 * All rights reserved.
Packit 78deda
 *
Packit 78deda
 * Permission to use, copy, modify, and distribute this software and its
Packit 78deda
 * documentation for any purpose, without fee, and without written agreement is
Packit 78deda
 * hereby granted, provided that the above copyright notice and the following
Packit 78deda
 * two paragraphs appear in all copies of this software.
Packit 78deda
 *
Packit 78deda
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
Packit 78deda
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
Packit 78deda
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
Packit 78deda
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 78deda
 *
Packit 78deda
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
Packit 78deda
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
Packit 78deda
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit 78deda
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
Packit 78deda
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.  */
Packit 78deda
Packit 78deda
#include <stdio.h>
Packit 78deda
#include <stdlib.h>
Packit 78deda
#include <unistd.h>
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "shhopt.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
#include "ppm.h"
Packit 78deda
Packit 78deda
typedef unsigned char uint8;
Packit 78deda
Packit 78deda
#define CHOP(x)     ((x < 0) ? 0 : ((x > 255) ? 255 : x))
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
struct CmdlineInfo {
Packit 78deda
    /* All the information the user supplied in the command line,
Packit 78deda
       in a form easy for the program to use.
Packit 78deda
    */
Packit 78deda
    const char * inputFileName;  /* Name of input file */
Packit 78deda
    unsigned int width;
Packit 78deda
    unsigned int height;
Packit 78deda
};
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
parseCommandLine(int argc, char ** argv,
Packit 78deda
                 struct CmdlineInfo * const cmdlineP) {
Packit 78deda
Packit 78deda
    optStruct3 opt;   /* Set by OPTENT3 */
Packit 78deda
    unsigned int option_def_index;
Packit 78deda
    optEntry * option_def;
Packit 78deda
Packit 78deda
    MALLOCARRAY_NOFAIL(option_def, 100);
Packit 78deda
Packit 78deda
    option_def_index = 0;   /* incremented by OPTENT3 */
Packit 78deda
    OPTENT3('w', "width",     OPT_UINT,  &cmdlineP->width,   NULL,         0);
Packit 78deda
    OPTENT3('h', "height",    OPT_UINT,  &cmdlineP->height,  NULL,         0);
Packit 78deda
    
Packit 78deda
    /* DEFAULTS */
Packit 78deda
    cmdlineP->width = 352;
Packit 78deda
    cmdlineP->height = 240;
Packit 78deda
Packit 78deda
    opt.opt_table = option_def;
Packit 78deda
    opt.short_allowed = TRUE;
Packit 78deda
    opt.allowNegNum = FALSE;
Packit 78deda
Packit 78deda
    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
Packit 78deda
Packit 78deda
    if (cmdlineP->width == 0)
Packit 78deda
        pm_error("The width cannot be zero.");
Packit 78deda
    if (cmdlineP->width % 2 != 0)
Packit 78deda
        pm_error("The width of an eyuv image must be an even number.  "
Packit 78deda
                 "You specified %u.", cmdlineP->width);
Packit 78deda
    if (cmdlineP->height == 0)
Packit 78deda
        pm_error("The height cannot be zero.");
Packit 78deda
    if (cmdlineP->height % 2 != 0)
Packit 78deda
        pm_error("The height of an eyuv image must be an even number.  "
Packit 78deda
                 "You specified %u.", cmdlineP->height);
Packit 78deda
Packit 78deda
Packit 78deda
    if (argc-1 == 0) 
Packit 78deda
        cmdlineP->inputFileName = "-";
Packit 78deda
    else if (argc-1 != 1)
Packit 78deda
        pm_error("Program takes zero or one argument (filename).  You "
Packit 78deda
                 "specified %u", argc-1);
Packit 78deda
    else
Packit 78deda
        cmdlineP->inputFileName = argv[1];
Packit 78deda
Packit 78deda
    free(option_def);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static uint8 ** 
Packit 78deda
allocUint8Array(unsigned int const cols,
Packit 78deda
                unsigned int const rows) {
Packit 78deda
Packit 78deda
    uint8 ** retval;
Packit 78deda
    unsigned int row;
Packit 78deda
Packit 78deda
    MALLOCARRAY(retval, rows);
Packit 78deda
    if (retval == NULL)
Packit 78deda
        pm_error("Unable to allocate storage for %u x %u byte array.",
Packit 78deda
                 cols, rows);
Packit 78deda
Packit 78deda
    for (row = 0; row < rows; ++row) {
Packit 78deda
        MALLOCARRAY(retval[row], cols);
Packit 78deda
        if (retval[row] == NULL)
Packit 78deda
            pm_error("Unable to allocate storage for %u x %u byte array.",
Packit 78deda
                     cols, rows);
Packit 78deda
    }
Packit 78deda
    return retval;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void 
Packit 78deda
freeUint8Array(uint8 **     const array,
Packit 78deda
               unsigned int const rows) {
Packit 78deda
Packit 78deda
    unsigned int row;
Packit 78deda
Packit 78deda
    for (row = 0; row < rows; ++row)
Packit 78deda
        free(array[row]);
Packit 78deda
Packit 78deda
    free(array);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
allocateStorage(unsigned int const cols,
Packit 78deda
                unsigned int const rows,
Packit 78deda
                uint8 ***    const orig_yP,
Packit 78deda
                uint8 ***    const orig_cbP,
Packit 78deda
                uint8 ***    const orig_crP) {
Packit 78deda
Packit 78deda
    *orig_yP  = allocUint8Array(cols, rows);
Packit 78deda
    *orig_cbP = allocUint8Array(cols, rows);
Packit 78deda
    *orig_crP = allocUint8Array(cols, rows);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
freeStorage(unsigned int const rows,
Packit 78deda
            uint8 **     const orig_y,
Packit 78deda
            uint8 **     const orig_cb,
Packit 78deda
            uint8 **     const orig_cr) {
Packit 78deda
    
Packit 78deda
    freeUint8Array(orig_y,  rows); 
Packit 78deda
    freeUint8Array(orig_cb, rows); 
Packit 78deda
    freeUint8Array(orig_cr, rows);
Packit 78deda
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void 
Packit 78deda
YUVtoPPM(FILE *       const ofP,
Packit 78deda
         unsigned int const cols,
Packit 78deda
         unsigned int const rows,
Packit 78deda
         uint8 **     const orig_y,
Packit 78deda
         uint8 **     const orig_cb,
Packit 78deda
         uint8 **     const orig_cr) { 
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Convert the YUV image in arrays orig_y[][], orig_cb[][], and orig_cr[][]
Packit 78deda
   to a PPM image and write it to file *ofP.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    pixel * const pixrow = ppm_allocrow(cols);
Packit 78deda
    
Packit 78deda
    unsigned int row;
Packit 78deda
Packit 78deda
    ppm_writeppminit(ofP, cols, rows, 255, FALSE);
Packit 78deda
Packit 78deda
    for (row = 0; row < rows; ++row) {
Packit 78deda
        unsigned int col;
Packit 78deda
Packit 78deda
        for (col = 0; col < cols; ++col) {
Packit 78deda
            int const y =  orig_y[row][col] - 16;
Packit 78deda
            int const u =  orig_cb[row/2][col/2] - 128;
Packit 78deda
            int const v =  orig_cr[row/2][col/2] - 128;
Packit 78deda
            long   tempR, tempG, tempB;
Packit 78deda
            int    r, g, b;
Packit 78deda
            /* look at yuvtoppm source for explanation */
Packit 78deda
Packit 78deda
            tempR = 104635*v + 76310*y;
Packit 78deda
            tempG = -25690*u + -53294*v + 76310*y;
Packit 78deda
            tempB = 132278*u + 76310*y;
Packit 78deda
            
Packit 78deda
            r = CHOP((int)(tempR >> 16));
Packit 78deda
            g = CHOP((int)(tempG >> 16));
Packit 78deda
            b = CHOP((int)(tempB >> 16));
Packit 78deda
            
Packit 78deda
            PPM_ASSIGN(pixrow[col], r, g, b);
Packit 78deda
        }
Packit 78deda
        ppm_writeppmrow(stdout, pixrow, cols, 255, FALSE);
Packit 78deda
    }
Packit 78deda
    ppm_freerow(pixrow);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void 
Packit 78deda
ReadYUV(FILE *       const ifP,
Packit 78deda
        unsigned int const cols,
Packit 78deda
        unsigned int const rows,
Packit 78deda
        uint8 **     const orig_y, 
Packit 78deda
        uint8 **     const orig_cb, 
Packit 78deda
        uint8 **     const orig_cr,
Packit 78deda
        bool *       const eofP) {
Packit 78deda
Packit 78deda
    unsigned int row;
Packit 78deda
    unsigned int totalRead;
Packit 78deda
    bool eof;
Packit 78deda
Packit 78deda
    eof = false;  /* initial value */
Packit 78deda
    totalRead = 0;  /* initial value */
Packit 78deda
Packit 78deda
    for (row = 0; row < rows && !eof; ++row) {        /* Y */
Packit 78deda
        size_t bytesRead;
Packit 78deda
Packit 78deda
        bytesRead = fread(orig_y[row], 1, cols, ifP);
Packit 78deda
        totalRead += bytesRead;
Packit 78deda
        if (bytesRead != cols)
Packit 78deda
            eof = true;
Packit 78deda
    }
Packit 78deda
        
Packit 78deda
    for (row = 0; row < rows / 2 && !eof; ++row) {  /* U */
Packit 78deda
        size_t bytesRead;
Packit 78deda
Packit 78deda
        bytesRead = fread(orig_cb[row], 1, cols / 2, ifP);
Packit 78deda
        totalRead += bytesRead;
Packit 78deda
        if (bytesRead != cols / 2)
Packit 78deda
            eof = true;
Packit 78deda
    }
Packit 78deda
        
Packit 78deda
    for (row = 0; row < rows / 2 && !eof; ++row) { /* V */
Packit 78deda
        size_t bytesRead;
Packit 78deda
Packit 78deda
        bytesRead = fread(orig_cr[row], 1, cols / 2, ifP);
Packit 78deda
        totalRead += bytesRead;
Packit 78deda
        if (bytesRead != cols / 2)
Packit 78deda
            eof = true;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if (eof) {
Packit 78deda
        if (totalRead == 0)
Packit 78deda
            *eofP = TRUE;
Packit 78deda
        else
Packit 78deda
            pm_error("Premature end of file reading EYUV input file");
Packit 78deda
    } else
Packit 78deda
        *eofP = FALSE;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int argc, const char **argv) {
Packit 78deda
Packit 78deda
    FILE * ifP;
Packit 78deda
    struct CmdlineInfo cmdline;
Packit 78deda
    unsigned int frameSeq;
Packit 78deda
Packit 78deda
    /* The following are addresses of malloc'ed storage areas for use by
Packit 78deda
       subroutines.
Packit 78deda
    */
Packit 78deda
    uint8 ** orig_y;
Packit 78deda
    uint8 ** orig_cb;
Packit 78deda
    uint8 ** orig_cr;
Packit 78deda
    bool eof;
Packit 78deda
Packit 78deda
    pm_proginit(&argc, argv);
Packit 78deda
Packit 78deda
    parseCommandLine(argc, (char **)argv, &cmdline);
Packit 78deda
Packit 78deda
    /* Allocate all the storage at once, to save time. */
Packit 78deda
    allocateStorage(cmdline.width, cmdline.height,
Packit 78deda
                    &orig_y, &orig_cb, &orig_cr);
Packit 78deda
Packit 78deda
    ifP = pm_openr(cmdline.inputFileName);
Packit 78deda
Packit 78deda
    for (frameSeq = 0, eof = false; !eof; ++frameSeq) {
Packit 78deda
Packit 78deda
        ReadYUV(ifP, cmdline.width, cmdline.height, 
Packit 78deda
                orig_y, orig_cb, orig_cr, &eof;;
Packit 78deda
Packit 78deda
        if (!eof) {
Packit 78deda
            pm_message("Converting Frame %u", frameSeq);
Packit 78deda
Packit 78deda
            YUVtoPPM(stdout, cmdline.width, cmdline.height,
Packit 78deda
                     orig_y, orig_cb, orig_cr);
Packit 78deda
        } else if (frameSeq == 0)
Packit 78deda
            pm_error("Empty EYUV input file");
Packit 78deda
    }
Packit 78deda
Packit 78deda
    freeStorage(cmdline.height, orig_y, orig_cb, orig_cr);
Packit 78deda
Packit 78deda
    pm_close(ifP);
Packit 78deda
Packit 78deda
    return 0;
Packit 78deda
}
Packit 78deda
Packit 78deda