/*------------------------------------------------------------------------
 *
 * Copyright (c) 1997-1998 by Cornell University.
 * 
 * See the file "license.txt" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * mpgtoppm.c
 * 
 * Wei Tsang Ooi weitsang@cs.cornell.edu
 *
 * Usage : mpgtoppm inputMPG
 *
 * Decodes an MPEG video into a series of PPM files.
 *
 *------------------------------------------------------------------------
 */
#include <sys/types.h>
#include <sys/stat.h>
#include "dvmbasic.h"
#include "dvmavi.h"
#include "dvmpnm.h"

/*
 * This procedure encode 3 byte image into a bitstream bs,
 * using bitparser bp, and output it to a tcl channel called
 * name.  Assumes that the header is already encoded in the 
 * bitstream.  (This is an improvement over the routines in pnmlib.tcl
 * since it reuse the same header and bitstream)
 */
void WritePPM (r, g, b, bs, bp, name) 
    ByteImage *r;
    ByteImage *g;
    ByteImage *b;
    BitStream *bs;
    BitParser *bp;
    char *name;
{
    FILE *chan;
    int curr;

    chan = fopen(name, "wb");
    if (chan == NULL) {
	fprintf(stderr, "unable to open %s for reading.\n", name);
	exit(1);
    }
    curr = BitParserTell(bp);
    PpmEncode(r, g, b, bp);
    BitStreamFileWrite(bs, chan, 0);
    BitParserSeek(bp, curr);
    fclose(chan);
}


int main(int argc, char *argv[])
{
    BitParser *outbp;
    BitStream *outbs;
    ByteImage *r, *g, *b;
    PnmHdr *pnmhdr;
    AviFile *aviFile;
    AviStream *aviStream;
    int seqw, seqh;
    int i, len;
    char outname[100];

    /*
     * Check arguments, open file, and initialize BitStream.
     */
    if (argc < 1) {
	fprintf(stderr, "usage : %s input\n", argv[0]);
	exit(1);
    }

    AVIFileInit();
    if (AviFileOpen(argv[1], &aviFile)) {
	fprintf(stderr, "unable to open %s as an avi file for reading.\n", argv[1]);
	exit(1);
    }

    if (AviStreamOpen(aviFile, 0, &aviStream)) {
	fprintf(stderr, "unable to open stream 0.\n", argv[1]);
	exit(1);
    }

    seqw = ((AviVideoStream *)aviStream->data)->width;
    seqh = ((AviVideoStream *)aviStream->data)->height;
    len = aviStream->length;

    r = ByteNew (seqw, seqh);
    g = ByteNew (seqw, seqh);
    b = ByteNew (seqw, seqh);

    /*
     * Create a new PnmHdr and encode it to the BitStream.  We only do
     * this once, since all frames have the same header.
     */
    pnmhdr = PnmHdrNew();
    PnmHdrSetType(pnmhdr, PPM_BIN);
    PnmHdrSetWidth(pnmhdr, seqw);
    PnmHdrSetHeight(pnmhdr, seqh);
    PnmHdrSetMaxVal(pnmhdr, 255);
    outbs = BitStreamNew(3*seqw*seqh + 20);
    outbp = BitParserNew();
    BitParserWrap(outbp, outbs);
    PnmHdrEncode(pnmhdr, outbp);
    PnmHdrFree(pnmhdr);

    AviStreamStartDecode(aviStream);
    for (i=0; i<len; i++) {
        AviVideoFrameRead(aviStream, r, g, b);
        sprintf(outname, "%03di.ppm", i);
        WritePPM(r, g, b, outbs, outbp, outname);
        fprintf(stderr, "Frame %d\n", i);
    }

    /*
     * Clean up the stuff.
     */
    ByteFree(r);
    ByteFree(g);
    ByteFree(b);
    AviStreamClose(aviStream);
    AviFileClose(aviFile);
    return 0;
}