/*------------------------------------------------------------------------
*
* 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.
*
*------------------------------------------------------------------------
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <dvmbasic.h>
#include <dvmmpeg.h>
#include <dvmcolor.h>
#include <dvmavi.h>
void swap (ByteImage **x, ByteImage **y)
{
ByteImage *temp;
temp = *x;
*x = *y;
*y = temp;
}
/*
*---------------------------------------------------------------
* This proc make sure that there are at least size bytes of
* data in the bitstream bs, which is attached to bitparser bp.
* If there is not enough data, fill up the bitstream by reading
* from tcl channel chan.
*---------------------------------------------------------------
*/
void CheckBitStreamUnderflow (bs, bp, chan, size)
BitStream *bs;
BitParser *bp;
FILE *chan;
int size;
{
int off = BitParserTell(bp);
int left = BitStreamBytesLeft(bs, off);
if (left < size) {
BitStreamShift (bs, off);
BitStreamFileRead (bs, chan, left);
BitParserSeek (bp, 0);
}
}
int main(int argc, char *argv[])
{
BitParser *bp = BitParserNew();
BitStream *bs = BitStreamNew(65536);
BitParser *outbp;
BitStream *outbs;
MpegSeqHdr *sh;
MpegPicHdr *fh;
ByteImage *r, *g, *b, *y, *u, *v, *br, *bg, *bb;
ByteImage *prevy, *prevu, *prevv, *futurey, *futureu, *futurev;
ScImage *scy, *scu, *scv;
VectorImage *fwdmv, *bwdmv;
AviFile *aviFile;
AviStream *aviStream;
FILE *file;
int codec, play_order, bnum=0, togo=0;
int currCode, len;
int halfw, halfh, w, h, seqw, seqh, picSize, remw, remh, counter, type;
if (argc < 4) {
fprintf(stderr, "usage : %s input output.avi codec\n", argv[0]);
exit(1);
}
file = fopen(argv[1], "rb");
if (file == NULL) {
fprintf(stderr, "unable to open %s for reading.\n", argv[1]);
exit(1);
}
BitStreamFileRead(bs, file, 0);
BitParserWrap(bp, bs);
sh = MpegSeqHdrNew();
MpegSeqHdrFind(bp);
MpegSeqHdrParse(bp, sh);
seqw = MpegSeqHdrGetWidth(sh);
seqh = MpegSeqHdrGetHeight(sh);
picSize = MpegSeqHdrGetBufferSize(sh);
remw = seqw % 16;
remh = seqh % 16;
if (remw != 0) {
w = seqw + 16 - remw;
} else {
w = seqw;
}
if (remh != 0) {
h = seqh + 16 - remh;
} else {
h = seqh;
}
halfw = w/2;
halfh = h/2;
y = ByteNew (w, h);
prevy = ByteNew (w, h);
futurey = ByteNew (w, h);
r = ByteNew (seqw, seqh);
g = ByteNew (seqw, seqh);
b = ByteNew (seqw, seqh);
br = ByteNew (seqw, seqh);
bg = ByteNew (seqw, seqh);
bb = ByteNew (seqw, seqh);
u = ByteNew (halfw, halfh);
prevu = ByteNew (halfw, halfh);
futureu = ByteNew (halfw, halfh);
v = ByteNew (halfw, halfh);
prevv = ByteNew (halfw, halfh);
futurev = ByteNew (halfw, halfh);
fwdmv = VectorNew (w/16, h/16);
bwdmv = VectorNew (w/16, h/16);
scy = ScNew (w/8, h/8);
scu = ScNew (w/16, h/16);
scv = ScNew (w/16, h/16);
fh = MpegPicHdrNew();
outbs = BitStreamNew(3*seqw*seqh + 20);
outbp = BitParserNew();
BitParserWrap(outbp, outbs);
len = MpegPicHdrFind(bp);
counter = 0;
AVIFileInit();
if (AviFileCreate(argv[2], &aviFile) != 0) {
fprintf(stderr, "unable to create avifile %s \n", argv[2]);
exit(1);
}
codec = mmioFOURCC(argv[3][0], argv[3][1], argv[3][2], argv[3][3]);
if (AviVideoStreamCreate (aviFile, codec, seqw, seqh,
15, 30, 75,
50000, &aviStream) != 0) {
fprintf(stderr, "unable to create avistream \n");
exit(1);
}
while (1) {
CheckBitStreamUnderflow(bs, bp, file, picSize);
MpegPicHdrParse(bp, fh);
play_order = MpegPicHdrGetTemporalRef(fh);
type = MpegPicHdrGetType(fh);
if (type == I_FRAME) {
swap(&futurey, &prevy);
swap(&futureu, &prevu);
swap(&futurev, &prevv);
MpegPicIParse(bp, sh, fh, scy, scu, scv);
ScIToByte(scy, y);
ScIToByte(scu, u);
ScIToByte(scv, v);
YuvToRgb420(y, u, v, r, g, b);
swap(&y, &futurey);
swap(&u, &futureu);
swap(&v, &futurev);
} else if (type == P_FRAME) {
swap(&futurey, &prevy);
swap(&futureu, &prevu);
swap(&futurev, &prevv);
MpegPicPParse(bp, sh, fh, scy, scu, scv, fwdmv);
ScPToY(scy, fwdmv, prevy, y);
ScPToUV(scu, fwdmv, prevu, u);
ScPToUV(scv, fwdmv, prevv, v);
YuvToRgb420(y, u, v, r, g, b);
swap(&y, &futurey);
swap(&u, &futureu);
swap(&v, &futurev);
} else {
MpegPicBParse(bp, sh, fh, scy, scu, scv, fwdmv, bwdmv);
ScBToY(scy, fwdmv, bwdmv, prevy, futurey, y);
ScBToUV(scu, fwdmv, bwdmv, prevu, futureu, u);
ScBToUV(scv, fwdmv, bwdmv, prevv, futurev, v);
YuvToRgb420(y, u, v, r, g, b);
}
/* Convert to display order */
if (play_order == togo) {
AviVideoFrameWrite(aviStream, r, g, b);
togo++;
if (bnum == togo) {
AviVideoFrameWrite(aviStream, br, bg, bb);
bnum=0;
togo++;
}
} else if(play_order > togo) {
swap(&r, &br);
swap(&g, &bg);
swap(&b, &bb);
bnum = play_order;
} else {
togo = 0;
if (play_order == togo) {
AviVideoFrameWrite(aviStream, r, g, b);
togo++;
} else {
swap(&r, &br);
swap(&g, &bg);
swap(&b, &bb);
bnum = play_order;
}
}
MpegPicHdrFind(bp);
currCode = MpegGetCurrStartCode(bp);
if (currCode == SEQ_END_CODE) {
break;
}
counter++;
printf("Frame %d\n", counter);
}
MpegPicHdrFree(fh);
MpegSeqHdrFree(sh);
BitStreamFree(bs);
BitParserFree(bp);
ByteFree(r);
ByteFree(g);
ByteFree(b);
ByteFree(br);
ByteFree(bg);
ByteFree(bb);
ByteFree(y);
ByteFree(u);
ByteFree(v);
ByteFree(prevy);
ByteFree(prevu);
ByteFree(prevv);
ByteFree(futurey);
ByteFree(futureu);
ByteFree(futurev);
ScFree(scy);
ScFree(scu);
ScFree(scv);
VectorFree(fwdmv);
VectorFree(bwdmv);
AviStreamClose(aviStream);
AviFileClose(aviFile);
return 0;
}