/*------------------------------------------------------------------------ * * 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. * * This is a simple example demonstrating how to encode a short sequence * of PPM files into I and P frames with: 1 Sequence, 2 GOPs, 4 Picture * frames per GOP, 1 Slice per frame, 1 quantization scale. The P frames * are encoded using the original I frames. The motion vector search is * done with full pel units. The frame pattern is IPIPIP... * * Note: the input files should be named <prefix>000.ppm, <prefix>001.ppm ... *------------------------------------------------------------------------ */ #include <sys/stat.h> #include <dvmbasic.h> #include <dvmmpeg.h> #include <dvmpnm.h> #include <dvmcolor.h> #define PREFIX_SIZE 100 /* prefix to the input files including directory */ #define BUFFER_SIZE 50000 /* large enough to hold 2 frames and some headers */ #define FRAMES_PER_SECOND 30 #define FORWARD_F_CODE 3 #define WIDTH 176 /* width and height of each frame in pixels */ #define HEIGHT 120 int fsize (char *name) { #ifdef __WIN32__ struct _stat s; #else struct stat s; #endif int result; result = stat(name, &s); return s.st_size; } int pictures = 0; int seconds = 0; int minutes = 0; int hours = 0; /* *------------------------------------------------------------------------ * Use this to keep track of how many picture frames, seconds, minutes, * hours. This information is encoded in the GOP headers. *------------------------------------------------------------------------ */ void IncrementTime() { pictures++; if ( pictures == FRAMES_PER_SECOND ) { pictures = 0; seconds++; if ( seconds == 60 ) { seconds = 0; minutes++; if ( minutes == 60 ) { minutes = 0; hours++; } } } } /* *------------------------------------------------------------------------ * Swap two ByteImage pointers *------------------------------------------------------------------------ */ void Swap(a, b) ByteImage **a, **b; { ByteImage *temp; temp = *a; *a = *b; *b = temp; } /* *------------------------------------------------------------------------ * Read in a PPM file into r, g, b ByteImages, then convert it to y, u, v * with 4:2:0 sampling *------------------------------------------------------------------------ */ #define READ_TO_YUV(bp, bs, r, g, b, y, u, v) {\ sprintf(fileName, "%s%03d.ppm", namePrefix, pictures);\ printf("Processing %s\n", fileName);\ inFile = fopen(fileName, "rb");\ if (inFile == NULL) {\ fprintf(stderr, "unable to open %s for reading.\n", fileName);\ exit(1);\ }\ BitParserWrap(bp, bs);\ BitStreamFileRead(bs, inFile, 0);\ PnmHdrParse(bp, pnmHdr);\ PpmParse(bp, r, g, b);\ fclose(inFile);\ RgbToYuv420(r, g, b, y, u, v);\ } int main(int argc, char *argv[]) { FILE *inFile, *outFile; char fileName[PREFIX_SIZE+3]; char namePrefix[PREFIX_SIZE]; BitParser *bp = BitParserNew(); /* input bitstream */ BitStream *bs; BitParser *obp = BitParserNew(); /* output bitstream */ BitStream *obs = BitStreamNew(BUFFER_SIZE); ByteImage *r, *g, *b, *y, *u, *v; ByteImage *prevY, *prevU, *prevV; ByteImage *qScale; ScImage *scY, *scU, *scV; VectorImage *fmv; /* forward motion vector */ PnmHdr *pnmHdr = PnmHdrNew(); MpegSeqHdr *seqHdr = MpegSeqHdrNew(); MpegGopHdr *gopHdr = MpegGopHdrNew(); MpegPicHdr *picHdr = MpegPicHdrNew(); int w = WIDTH, h = HEIGHT; int halfw = w/2; int halfh = h/2; int mbw = (w + 15) / 16; int mbh = (h + 15) / 16; int sliceInfo[] = {1000}; /* this should be enough for one frame */ int sliceInfoLen = 1; int gop, pic, temporalRef; r = ByteNew(w, h); g = ByteNew(w, h); b = ByteNew(w, h); y = ByteNew(w, h); prevY = ByteNew(w, h); u = ByteNew(halfw, halfh); prevU = ByteNew(halfw, halfh); v = ByteNew(halfw, halfh); prevV = ByteNew(halfw, halfh); qScale = ByteNew(mbw, mbh); scY = ScNew(mbw*2, mbh*2); scU = ScNew(mbw, mbh); scV = ScNew(mbw, mbh); fmv = VectorNew(mbw, mbh); if (argc < 2) { fprintf(stderr, "Not enough parameters : %s <input file prefix> <output file name>\n", argv[0]); exit(1); } /* Get input file size */ strcpy(namePrefix, argv[1]); sprintf(fileName, "%s000.ppm", namePrefix); inFile = fopen(fileName, "rb"); if (inFile == NULL) { fprintf(stderr, "unable to open %s for reading.\n", fileName); exit(1); } bs = BitStreamNew(fsize(fileName)); fclose(inFile); /* Create outfile file */ outFile = fopen(argv[2], "wb"); if (outFile == NULL) { fprintf(stderr, "unable to open %s for writing.\n", argv[2]); exit(1); } BitParserWrap(obp, obs); ByteSet(qScale, 4); MpegSeqHdrSetWidth(seqHdr, w); MpegSeqHdrSetHeight(seqHdr, h); MpegSeqHdrSetAspectRatio(seqHdr, 1.000); MpegSeqHdrSetPicRate(seqHdr, FRAMES_PER_SECOND); MpegSeqHdrSetBitRate(seqHdr, -1); MpegSeqHdrSetBufferSize(seqHdr, 16); MpegSeqHdrSetConstrained(seqHdr, 0); MpegSeqHdrSetDefaultIQT(seqHdr); MpegSeqHdrSetDefaultNIQT(seqHdr); MpegSeqHdrEncode(seqHdr, obp); /* we are not going to change these */ MpegGopHdrSetDropFrameFlag(gopHdr, 0); MpegGopHdrSetClosedGop(gopHdr, 0); MpegGopHdrSetBrokenLink(gopHdr, 0); MpegPicHdrSetVBVDelay(picHdr, 0); MpegPicHdrSetFullPelBackward(picHdr, 0); MpegPicHdrSetBackwardFCode(picHdr, 0); for (gop = 0; gop < 2; gop++) { MpegGopHdrSetHours(gopHdr, hours); MpegGopHdrSetMinutes(gopHdr, minutes); MpegGopHdrSetSeconds(gopHdr, seconds); MpegGopHdrSetPictures(gopHdr, pictures); MpegGopHdrEncode(gopHdr, obp); temporalRef = 0; for (pic = 0; pic < 2; pic++) { /* I FRAME */ READ_TO_YUV(bp, bs, r, g, b, y, u, v); MpegPicHdrSetTemporalRef(picHdr, temporalRef); MpegPicHdrSetType(picHdr, I_FRAME); MpegPicHdrSetFullPelForward(picHdr, 0); MpegPicHdrSetForwardFCode(picHdr, 0); MpegPicHdrEncode (picHdr, obp); ByteToScI(y, qScale, MPEG_INTRA, scY); /* MPEG_INTRA is the default quantizer table */ ByteToScI(u, qScale, MPEG_INTRA, scU); ByteToScI(v, qScale, MPEG_INTRA, scV); MpegPicIEncode (picHdr, scY, scU, scV, qScale, sliceInfo, sliceInfoLen, obp); IncrementTime(); temporalRef++; Swap(&y, &prevY); Swap(&u, &prevU); Swap(&v, &prevV); /* P FRAME */ READ_TO_YUV(bp, bs, r, g, b, y, u, v); MpegPicHdrSetTemporalRef(picHdr, temporalRef); MpegPicHdrSetType(picHdr, P_FRAME); MpegPicHdrSetFullPelForward(picHdr, 1); MpegPicHdrSetForwardFCode(picHdr, FORWARD_F_CODE); MpegPicHdrEncode (picHdr, obp); BytePMotionVecSearch(picHdr, y, prevY, NULL, fmv); ByteYToScP (y, prevY, fmv, qScale, MPEG_INTRA, MPEG_NON_INTRA, scY); ByteUVToScP(u, prevU, fmv, qScale, MPEG_INTRA, MPEG_NON_INTRA, scU); ByteUVToScP(v, prevV, fmv, qScale, MPEG_INTRA, MPEG_NON_INTRA, scV); MpegPicPEncode (picHdr, scY, scU, scV, fmv, qScale, sliceInfo, sliceInfoLen, obp); IncrementTime(); temporalRef++; /* write two frames to the bitstream */ printf("Writing to file...\n"); BitStreamFileWriteSegment(obs, outFile, 0, BitParserTell(obp)); BitParserWrap(obp, obs); } } /* done forget this */ MpegSeqEndCodeEncode(obp); BitStreamFileWriteSegment(obs, outFile, 0, BitParserTell(obp)); /* lots of things to free up */ BitStreamFree(bs); BitParserFree(bp); BitStreamFree(obs); BitParserFree(obp); MpegSeqHdrFree(seqHdr); MpegGopHdrFree(gopHdr); MpegPicHdrFree(picHdr); PnmHdrFree(pnmHdr); ByteFree(r); ByteFree(g); ByteFree(b); ByteFree(y); ByteFree(u); ByteFree(v); ByteFree(prevY); ByteFree(prevU); ByteFree(prevV); ByteFree(qScale); ScFree(scY); ScFree(scU); ScFree(scV); VectorFree(fmv); return 0; }