summaryrefslogtreecommitdiffstats
path: root/mpeglib/lib/mpegplay/videoDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mpeglib/lib/mpegplay/videoDecoder.cpp')
-rw-r--r--mpeglib/lib/mpegplay/videoDecoder.cpp476
1 files changed, 476 insertions, 0 deletions
diff --git a/mpeglib/lib/mpegplay/videoDecoder.cpp b/mpeglib/lib/mpegplay/videoDecoder.cpp
new file mode 100644
index 00000000..b1971795
--- /dev/null
+++ b/mpeglib/lib/mpegplay/videoDecoder.cpp
@@ -0,0 +1,476 @@
+/*
+ mpeg I video decoder (derived from mpeg_play)
+ Copyright (C) 2000 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#include "videoDecoder.h"
+
+using namespace std;
+
+
+
+VideoDecoder::VideoDecoder(MpegVideoStream* inputStream,
+ MpegVideoHeader* initSequence) {
+
+ /* Check for legal buffer length. */
+
+ init_tables();
+
+
+ /* Initialize fields that used to be global */
+
+ mpegVideoStream=inputStream;
+ decoderClass=new DecoderClass(this,mpegVideoStream);
+ recon=new Recon();
+ motionVector=new MotionVector();
+ slice=new Slice();
+ group=new GOP();
+ mpegVideoHeader=new MpegVideoHeader();
+ picture=new Picture();
+ macroBlock=new MacroBlock(this);
+
+ // init this stream with the init sequence
+ initSequence->copyTo(mpegVideoHeader);
+
+ syncState=SYNC_TO_CLOSED_GOP;
+ extension=new MpegExtension();
+ frameCounter=0;
+}
+
+
+VideoDecoder::~VideoDecoder() {
+
+ delete mpegVideoHeader;
+ delete picture;
+ delete decoderClass;
+ delete recon;
+ delete motionVector;
+ delete slice;
+ delete group;
+ delete extension;
+ delete macroBlock;
+}
+
+
+
+
+
+/*
+ *--------------------------------------------------------------
+ *
+ * mpegVidRsrc --
+ *
+ * Parses bit stream until MB_QUANTUM number of
+ * macroblocks have been decoded or current slice or
+ * picture ends, whichever comes first. If the start
+ * of a frame is encountered, the frame is time stamped
+ * with the value passed in time_stamp. If the value
+ * passed in buffer is not null, the video stream buffer
+ * is set to buffer and the length of the buffer is
+ * expected in value passed in through length. The current
+ * video stream is set to vid_stream. If vid_stream
+ * is passed as NULL, a new VideoDecoder structure is created
+ * and initialized and used as the current video stream.
+ *
+ * Results:
+ * A pointer to the video stream structure used.
+ *
+ * Side effects:
+ * Bit stream is irreversibly parsed. If a picture is completed,
+ * a function is called to display the frame at the correct time.
+ *
+ *--------------------------------------------------------------
+ */
+
+int VideoDecoder::mpegVidRsrc(PictureArray* pictureArray) {
+ int back=_SYNC_TO_NONE;
+
+ unsigned int data;
+ int i;
+
+
+ /*
+ * If called for the first time, find start code, make sure it is a
+ * sequence start code.
+ */
+
+
+ /* Get next 32 bits (size of start codes). */
+
+ data=mpegVideoStream->showBits(32);
+
+
+ /*
+ * Process according to start code (or parse macroblock if not a start code
+ * at all).
+ */
+ switch (data) {
+ /*
+ case PACK_START_CODE:
+ case SYSTEM_HEADER_START_CODE:
+ cout << "Packet in Loop **************"<<endl;
+ mpegVideoStream->flushBits(32);
+ packet->read_sys(data,vid_stream->bufferReader);
+ */
+ case SEQ_END_CODE:
+ case ISO_11172_END_CODE: /* handle ISO_11172_END_CODE too */
+
+ /* Display last frame. */
+
+ // removed!
+
+ /* Sequence done. Do the right thing. For right now, exit. */
+
+
+ cout << "******** flushin end code"<<endl;
+ mpegVideoStream->flushBits(32);
+ goto done;
+ break;
+ case EXT_START_CODE:
+ cout << "found EXT_START_CODE skipping"<<endl;
+ mpegVideoStream->flushBits(32);
+ /* Goto next start code. */
+ mpegVideoStream->next_start_code();
+
+ break;
+ case USER_START_CODE:
+ mpegVideoStream->flushBits(32);
+ /* Goto next start code. */
+ mpegVideoStream->next_start_code();
+
+ break;
+ case SEQ_START_CODE:
+
+ /* Sequence start code. Parse sequence header. */
+ if (ParseSeqHead() == false) {
+ printf("SEQ_START_CODE 1-error\n");
+ goto error;
+ }
+ goto done;
+
+ case GOP_START_CODE:
+ /* Group of Pictures start code. Parse gop header. */
+ if (ParseGOP() == false) {
+ printf("GOP_START_CODE 1-error\n");
+ goto error;
+ }
+ goto done;
+
+ case PICTURE_START_CODE:
+
+ /* Picture start code. Parse picture header and first slice header. */
+
+
+ back=ParsePicture();
+ if (back != _SYNC_TO_NONE) {
+ //cout << "skip B Frame we are late"<<endl;
+ return back;
+ }
+
+ // parse ok
+ if (ParseSlice() == false) {
+ printf("PICTURE_START_CODE 2-error\n");
+ goto error;
+ }
+ break;
+
+ case SEQUENCE_ERROR_CODE:
+ mpegVideoStream->flushBits(32);
+ mpegVideoStream->next_start_code();
+
+ goto done;
+
+
+ default:
+
+ /* Check for slice start code. */
+ if ((data >= SLICE_MIN_START_CODE) && (data <= SLICE_MAX_START_CODE)) {
+
+ /* Slice start code. Parse slice header. */
+ if (ParseSlice() == false) {
+ printf("default 1-error\n");
+ goto error;
+ }
+ }
+ break;
+ }
+
+ /* Parse next MB_QUANTUM macroblocks. */
+ for (i = 0; i < MB_QUANTUM; i++) {
+
+ /* Check to see if actually a startcode and not a macroblock. */
+ data=mpegVideoStream->showBits(23);
+ if (data != 0x0) {
+ /* Not start code. Parse Macroblock. fill yuv pictures*/
+ if (macroBlock->processMacroBlock(pictureArray) == false) {
+ goto error;
+ }
+ } else {
+ /* Not macroblock, actually start code. Get start code. */
+ mpegVideoStream->next_start_code();
+
+ /*
+ * If start code is outside range of slice start codes, frame is
+ * complete, display frame.
+ */
+ data=mpegVideoStream->showBits(32);
+
+ if (((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) &&
+ (data != SEQUENCE_ERROR_CODE)) {
+ doPictureDisplay(pictureArray);
+ }
+ goto done;
+ }
+ }
+ data=mpegVideoStream->showBits(23);
+ /* Check if we just finished a picture on the MB_QUANTUM macroblock */
+ if (data == 0x0) {
+ mpegVideoStream->next_start_code();
+
+ data=mpegVideoStream->showBits(32);
+ if ((data < SLICE_MIN_START_CODE) || (data > SLICE_MAX_START_CODE)) {
+ doPictureDisplay(pictureArray);
+ }
+ }
+
+ /* Return pointer to video stream structure. */
+
+ goto done;
+
+error:
+ init_tables();
+ back=_SYNC_TO_GOP;
+ mpegVideoHeader->init_quanttables();
+
+ goto done;
+
+done:
+ return back;
+
+}
+
+
+
+
+
+
+int VideoDecoder::ParseSeqHead() {
+ int back;
+
+ /* Flush off sequence start code. */
+
+ mpegVideoStream->flushBits(32);
+
+ back=mpegVideoHeader->parseSeq(mpegVideoStream);
+
+ return back;
+
+}
+
+
+
+
+int VideoDecoder::ParseGOP() {
+ if (syncState==SYNC_TO_CLOSED_GOP) {
+ syncState=SYNC_HAS_CLOSED_GOP;
+ }
+
+ return group->processGOP(mpegVideoStream);
+}
+
+
+
+
+int VideoDecoder::ParsePicture() {
+ int back;
+ back=picture->processPicture(mpegVideoStream);
+
+ macroBlock->resetPastMacroBlock();
+ if (back == false) {
+ return _SYNC_TO_GOP;
+ }
+
+
+ return _SYNC_TO_NONE;
+}
+
+
+
+int VideoDecoder::ParseSlice() {
+
+
+ slice->parseSlice(mpegVideoStream);
+ macroBlock->resetMacroBlock();
+ decoderClass->resetDCT();
+ return true;
+}
+
+
+
+
+/**
+ After a seek we can only start with an I frame
+*/
+
+void VideoDecoder::resyncToI_Frame() {
+
+ syncState=SYNC_TO_CLOSED_GOP;
+}
+
+
+void VideoDecoder::doPictureDisplay(PictureArray* pictureArray) {
+
+
+ // insert end timestamp to current picture
+ YUVPicture* pic=pictureArray->getCurrent();
+ unsigned int code_type=picture->getCodeType();
+
+ TimeStamp* startTimeStamp=picture->getStartOfPicStamp();
+
+ pic->setStartTimeStamp(startTimeStamp);
+ float rate=mpegVideoHeader->getPictureRate();
+
+ pictureArray->setPicturePerSecond(rate);
+
+
+
+ pic->setMpegPictureType(code_type);
+
+ if (syncState < SYNC_HAS_CLOSED_GOP) {
+ return;
+ }
+ if (syncState < SYNC_HAS_I_FRAME_SYNC) {
+ if (code_type != I_TYPE) {
+ return;
+ }
+ }
+ if (code_type == I_TYPE) {
+ YUVPicture* past=pictureArray->getPast();
+ YUVPicture* future=pictureArray->getFuture();
+ YUVPicture* current=pictureArray->getCurrent();
+
+ YUVPicture* tmp=past;
+ past = future;
+ future = current;
+ current = tmp;
+
+ pic=past;
+
+
+ pictureArray->setPast(past);
+ pictureArray->setCurrent(current);
+ pictureArray->setFuture(future);
+
+ if (syncState < SYNC_HAS_I_FRAME_SYNC) {
+ syncState=SYNC_HAS_I_FRAME_SYNC;
+ return;
+ }
+ if (syncState == SYNC_HAS_P_FRAME_SYNC) {
+ syncState=SYNC_HAS_FRAME_SYNC;
+ return;
+ }
+ if (syncState == SYNC_HAS_I_FRAME_SYNC) {
+ syncState=SYNC_HAS_P_FRAME_SYNC;
+ return;
+ }
+
+
+
+ }
+
+ if (code_type == P_TYPE) {
+ YUVPicture* past=pictureArray->getPast();
+ YUVPicture* future=pictureArray->getFuture();
+ YUVPicture* current=pictureArray->getCurrent();
+
+ YUVPicture* tmp=past;
+ past = future;
+ future = current;
+ current = tmp;
+
+ pic = past;
+
+
+
+ pictureArray->setPast(past);
+ pictureArray->setCurrent(current);
+ pictureArray->setFuture(future);
+
+ if (syncState < SYNC_HAS_P_FRAME_SYNC) {
+ syncState=SYNC_HAS_P_FRAME_SYNC;
+ return;
+ }
+
+ }
+ if (code_type == B_TYPE) {
+ if (syncState == SYNC_HAS_P_FRAME_SYNC) {
+ syncState=SYNC_HAS_FRAME_SYNC;
+ YUVPicture* past=pictureArray->getPast();
+ pic=past;
+ }
+ /**
+ Now check for PTS timeStamp error. It seems some encoders
+ handles this different.
+ If the P frame has a timeStamp earlier than our B stamp
+ we swap them.
+ */
+ YUVPicture* pframe=pictureArray->getFuture();
+ YUVPicture* bframe=pictureArray->getCurrent();
+
+ TimeStamp* pTime=pframe->getStartTimeStamp();
+ TimeStamp* bTime=bframe->getStartTimeStamp();
+
+ double pPTS=pTime->getPTSTimeStamp();
+ double bPTS=bTime->getPTSTimeStamp();
+ if (pPTS < bPTS) {
+ //cout << "********P/B Frame PTS error -> enable swap and pray"<<endl;
+ bTime->copyTo(pTime);
+ }
+
+
+
+ // we display the current picture
+ // (already set)
+ }
+
+
+ if (pic == NULL) {
+ cout << "pic NULL"<<endl;
+ exit(0);
+ return;
+ }
+ if (syncState < SYNC_HAS_FRAME_SYNC) {
+ return;
+ }
+
+ double val=pictureArray->getPicturePerSecond();
+ pic->setPicturePerSecond(val);
+
+ TimeStamp* currentStamp=pic->getStartTimeStamp();
+
+
+ frameCounter++;
+
+ if (currentStamp->getPTSFlag()==true) {
+ frameCounter=0;
+ }
+ currentStamp->setVideoFrameCounter(frameCounter);
+
+
+ // let plugin "rip" the picture
+ pictureArray->setYUVPictureCallback(pic);
+}
+
+
+
+
+