theonlineoasis

VideoCodec/Modules/Pipeline/Pipeline.cpp

#include "Pipeline.h" using namespace std; namespace VideoCodec {    Pipeline::Pipeline() : Module(PIPELINE_MODULE_ID)    {    }        Pipeline::~Pipeline()    {    }        ConfigurationStatus Pipeline::Configure(ConfigurationElement* configurationElement)    {       if (configurationElement != NULL && configurationElement->GetValue("type") != NULL)       {          if (*configurationElement->GetValue("type")->GetString() == string("simpleFrames"))             this->type = SIMPLE_FRAMES_PIPELINE;          else if (*configurationElement->GetValue("type")->GetString() == string("encodeFramesToFile"))             this->type = ENCODE_FRAMES_TO_FILE;          else if (*configurationElement->GetValue("type")->GetString() == string("decodeFileToFrames"))             this->type = DECODE_FILE_TO_FRAMES;          else if (*configurationElement->GetValue("type")->GetString() == string("encodeFramesToFileWithPrediction"))             this->type = ENCODE_FRAMES_TO_FILE_WITH_PREDICTION;                    this->diagnosticOutputResiduals = (configurationElement->GetValue("diagnosticOutputResiduals") != NULL && *(configurationElement->GetValue("diagnosticOutputResiduals")->GetString()) == "true");          this->diagnosticShowVectors = (configurationElement->GetValue("diagnosticShowVectors") != NULL && *(configurationElement->GetValue("diagnosticShowVectors")->GetString()) == "true");          this->diagnosticPerformanceTimingInLoop = (configurationElement->GetValue("diagnosticPerformanceTimingInLoop") != NULL && *(configurationElement->GetValue("diagnosticPerformanceTimingInLoop")->GetString()) == "true");          this->diagnosticPerformanceTimingPerLoop = (configurationElement->GetValue("diagnosticPerformanceTimingPerLoop") != NULL && *(configurationElement->GetValue("diagnosticPerformanceTimingPerLoop")->GetString()) == "true");          this->diagnosticPerformanceTimingGlobal = (configurationElement->GetValue("diagnosticPerformanceTimingGlobal") != NULL && *(configurationElement->GetValue("diagnosticPerformanceTimingGlobal")->GetString()) == "true");          this->diagnosticPerformanceBits = (configurationElement->GetValue("diagnosticPerformanceBits") != NULL && *(configurationElement->GetValue("diagnosticPerformanceBits")->GetString()) == "true");          this->mv4 = (configurationElement->GetValue("mv4") != NULL && *(configurationElement->GetValue("mv4")->GetString()) == "true");                    return MODULE_CONFIGURATION_OK;       }       else       {          this->type = INVALID_PIPELINE;          this->diagnosticOutputResiduals = false;          this->diagnosticPerformanceTimingInLoop = false;          this->diagnosticPerformanceTimingPerLoop = false;          this->diagnosticPerformanceTimingGlobal = false;                    return MODULE_CONFIGURATION_ERROR;       }    }        void Pipeline::Run(Codec* codec)    {       // Based on the choice of coding path, get a set of modules and pass a PictureInfo instance through.       if (this->type == SIMPLE_FRAMES_PIPELINE)       {          // The simple frames pipeline takes a set of image files, and prepares them for coding.          // The frames are then decompressed and output to individual frame files.                    // Retrieve configured modules from the encoder.          FrameInputModule* input = (FrameInputModule*)codec->GetModule(std::string(FRAME_INPUT_MODULE_ID));          FrameOutputModule* output = (FrameOutputModule*)codec->GetModule(std::string(FRAME_OUTPUT_MODULE_ID));                    ColourSpaceConverter* yuvConverter = (ColourSpaceConverter*)codec->GetModule(std::string(COLOUR_SPACE_CONVERTER_MODULE_ID));          MacroblockHandler* macroblockHandler = (MacroblockHandler*)codec->GetModule(std::string(MACROBLOCK_HANDLER_MODULE_ID));          AANDCT* dct = (AANDCT*)codec->GetModule(std::string(AAN_DCT_MODULE_ID));          DCTCoefficientQuantizer* dctCoefficientQuantizer = (DCTCoefficientQuantizer*)codec->GetModule(std::string(DCT_COEFFICIENT_QUANTIZER_MODULE_ID));                    // Check that the required modules are non-NULL.          if (input == NULL || output == NULL ||             yuvConverter == NULL || macroblockHandler == NULL || dct == NULL || dctCoefficientQuantizer == NULL)          {             Logger::LogMessage("One of the modules required by this pipeline could not be retrieved.");             return;          }                    int framesProcessedCount = 0;          while (input->HasFrames())          {             // Get scan order pixel data in RGB format.             PictureInfo* thisFrame = input->FetchNextFrame();             thisFrame->SetFrameType(FRAME_TYPE_INTRA);                          // Convert to YUV.             yuvConverter->ConvertRGBToYUVRepresentation(thisFrame, codec);                          // Change the pixel layout from scan order to macroblock layout.             macroblockHandler->ConvertScanToMacroblockLayout(thisFrame);                          // Perform a discrete cosine transform to compress entropy in the top left of each block.             dct->PictureDCT(thisFrame);                          // Quantize the coefficients in place.             dctCoefficientQuantizer->QuantizeDCTCoefficients(thisFrame, false);                          // Dequantize the coefficients in place.             dctCoefficientQuantizer->DequantizeDCTCoefficients(thisFrame, false);                          // Perform an inverse discrete cosine transform to get back to the normal spatial representation for each block.             dct->PictureIDCT(thisFrame);                          // Change the pixel layout back to the scan order.             macroblockHandler->ConvertMacroblockToScanLayout(thisFrame);                          // Go back to the RGB colour space.             yuvConverter->ConvertYUVToRGBRepresentation(thisFrame);                          // Write out the data.             output->WriteImage(thisFrame, framesProcessedCount);                          // Clean up the picture information.             delete thisFrame;             // Processing of this frame is complete.             Logger::LogMessage("Processed a frame.");             framesProcessedCount++;          }       }       else if (this->type == ENCODE_FRAMES_TO_FILE || this->type == ENCODE_FRAMES_TO_FILE_WITH_PREDICTION)       {          this->encodePath(codec);       }       else if (this->type == DECODE_FILE_TO_FRAMES)       {          this->decodePath(codec);       }       else       {          Logger::LogMessage("Unsupported pipeline selected.");       }    }        void Pipeline::codeFrame(PictureInfo* thisFrame, FrameDataBitLength codedLength, StreamFormatter* formatter, HuffmanEntropyEncoder* entropyEncoder, DCTCoefficientQuantizationMethod quantizationMethod, UnsignedByte quantizationScale, bool mv4)    {       // Output the frame header data.       formatter->OutputFrameHeader(thisFrame->GetFrameType() == FRAME_TYPE_INTER, quantizationMethod, quantizationScale);              // Build the VLC stream.       BinaryStreamBuilder* streamBuilder = new BinaryStreamBuilder();       streamBuilder->AllocateStream(codedLength);       entropyEncoder->EncodeFrame(thisFrame, streamBuilder, mv4);              // Finish writing to the stream by aligning with the next byte boundary, then get the data.       streamBuilder->AlignStream();              // Output the data into the file stream.       unsigned char* bitStream = streamBuilder->GetStream();       formatter->OutputFrame(bitStream, streamBuilder->GetWrittenBitCount() >> 3);       delete [] bitStream;       delete streamBuilder;    }        void Pipeline::encodePath(Codec* codec)    {       // If this is false, all frames will be key-frames.       bool prediction = this->type == ENCODE_FRAMES_TO_FILE_WITH_PREDICTION;              // Retrieve configured modules from the encoder.       FrameInputModule* input = (FrameInputModule*)codec->GetModule(std::string(FRAME_INPUT_MODULE_ID));       StreamOutputModule* output = (StreamOutputModule*)codec->GetModule(std::string(STREAM_OUTPUT_MODULE_ID));       StreamFormatter* formatter = (StreamFormatter*)codec->GetModule(std::string(STREAM_FORMATTER_MODULE_ID));       ColourSpaceConverter* yuvConverter = (ColourSpaceConverter*)codec->GetModule(std::string(COLOUR_SPACE_CONVERTER_MODULE_ID));       MacroblockHandler* macroblockHandler = (MacroblockHandler*)codec->GetModule(std::string(MACROBLOCK_HANDLER_MODULE_ID));       AANDCT* dct = (AANDCT*)codec->GetModule(std::string(AAN_DCT_MODULE_ID));       DCTCoefficientQuantizer* dctCoefficientQuantizer = (DCTCoefficientQuantizer*)codec->GetModule(std::string(DCT_COEFFICIENT_QUANTIZER_MODULE_ID));       HuffmanEntropyEncoder* entropyEncoder = (HuffmanEntropyEncoder*)codec->GetModule(std::string(HUFFMAN_ENTROPY_ENCODER_MODULE_ID));       ProgressInformation* progress = (ProgressInformation*)codec->GetModule(std::string(PROGRESS_INFORMATION_MODULE_ID));       External* external = (External*)codec->GetModule(std::string(EXTERNAL_MODULE_ID));              // For predictive frames:       GOPManager* gopManager = NULL;       FrameDifference* frameDifference = NULL;       MotionEstimation* motionEstimation = NULL;       RateControl* rateControl = NULL;       if (prediction)       {          gopManager = (GOPManager*)codec->GetModule(std::string(GOP_MANAGER_MODULE_ID));          frameDifference = (FrameDifference*)codec->GetModule(std::string(FRAME_DIFFERENCE_MODULE_ID));          motionEstimation = (MotionEstimation*)codec->GetModule(std::string(MOTION_ESTIMATION_MODULE_ID));          rateControl = (RateControl*)codec->GetModule(std::string(RATE_CONTROL_MODULE_ID));          if (this->mv4)             motionEstimation->EnableMV4();       }              // Check that the required modules are non-NULL.       if (input == NULL || output == NULL ||          yuvConverter == NULL || macroblockHandler == NULL || dct == NULL || dctCoefficientQuantizer == NULL || entropyEncoder == NULL ||          progress == NULL || external == NULL ||          (prediction && (gopManager == NULL || frameDifference == NULL || motionEstimation == NULL || rateControl == NULL)))       {          Logger::LogMessage("One of the modules required by this pipeline was not specified. Make sure that it is enabled at the command line.");          return;       }              // To write the data to the stream:       // 1. Open the stream output file and write the format header.       // 2. Write a stream header based on the first frame's dimensions.       // 3. Write frame headers then frame data, for each frame in the stream.       //       // The GOPManager holds a reference frame which consists of byte-based pixel data in scan order.              // Open the output stream for writing. Attach the stream to the stream formatter.       output->OpenFile();       formatter->SetOutputModule(output);              // Write the file format information header.       formatter->OutputFormatHeader();              // Keep a reference frame in unsigned byte format.       PictureInfo* reference = NULL;              // Performance details in a map. Each integer value has an associated string and integer. startTimes are also stored for performance timers.       std::map<pair<const char*, FrameCount>, int64_t> performanceDetails;       int64_t startTimes[10];       startTimes[0] = startTimes[1] = startTimes[2] = startTimes[3] = 0;       // Keep track of how many frames we've processed, and the number of bits encoded (will only be valid when performance bit counting is enabled).       FrameCount framesProcessedCount = 0;       int64_t performanceStreamBits = 0;              // Set up global timing.       if (this->diagnosticPerformanceTimingGlobal)          PERFORMANCE_TIMING_BEFORE(1);              while (input->HasFrames())       {          // The current frame.          PictureInfo* thisFrame = input->FetchNextFrame();                    // Configure this frame based on the input frame and the status of prediction/the reference frame.          thisFrame->SetFrameType(!prediction || reference == NULL || (gopManager->RequireIFrame()) ? FRAME_TYPE_INTRA : FRAME_TYPE_INVALID);          thisFrame->SetBlockColumns(thisFrame->GetPixelsX() >> 4);          thisFrame->SetBlockRows(thisFrame->GetPixelsY() >> 4);                    // Output the stream header if this is the first frame.          if (framesProcessedCount == 0)             formatter->OutputStreamHeader(input->GetTotalFrameCount(), thisFrame->GetBlockColumns(), thisFrame->GetBlockRows(), this->mv4, motionEstimation->UseSubPixel());                    // Frame timing.          if (this->diagnosticPerformanceTimingPerLoop)          {             PERFORMANCE_TIMING_BEFORE(2);          }                    // Convert to YUV.          PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);          yuvConverter->ConvertRGBToYUVRepresentation(thisFrame, codec);          PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Colour space conversion",framesProcessedCount);                    if (thisFrame->GetFrameType() == FRAME_TYPE_INTRA)          {             // This frame is encoded as a key-frame.             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             macroblockHandler->ConvertScanToMacroblockLayout(thisFrame);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: To macroblock layout",framesProcessedCount);             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             dct->PictureDCT(thisFrame);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Whole picture DCT",framesProcessedCount);             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             dctCoefficientQuantizer->QuantizeDCTCoefficients(thisFrame, false);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Coefficient quantization",framesProcessedCount);                          PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             FrameDataBitLength codedLength = entropyEncoder->GetFrameCodedLength(thisFrame, mv4);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Entropy coding length only",framesProcessedCount);             PERFORMANCE_BITS((int64_t)codedLength, "Required I-frame: Bits coded", framesProcessedCount);                          PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             this->codeFrame(thisFrame, codedLength, formatter, entropyEncoder, dctCoefficientQuantizer->GetIntraQuantizationMethod(), dctCoefficientQuantizer->GetIntraQuantizationScale(), mv4);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Entropy coding",framesProcessedCount);                          // Compute the new reference frame.             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             dctCoefficientQuantizer->DequantizeDCTCoefficients(thisFrame, false);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Coefficient dequantization for reference",framesProcessedCount);             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             dct->PictureIDCT(thisFrame);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: Whole picture IDCT for reference",framesProcessedCount);                          PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             macroblockHandler->ConvertMacroblockToScanLayout(thisFrame);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Required I-frame: To scan layout for reference",framesProcessedCount);                          // We no longer require the old reference. Set the reference to be this frame.             if (reference != NULL)                delete reference;             reference = thisFrame;             gopManager->Reset();                          Logger::LogMessage("I");          }          else          {             // Prepare the residual frame.             PictureInfo* residual = thisFrame->Clone();             thisFrame->SetFrameType(FRAME_TYPE_INTRA);             residual->SetFrameType(FRAME_TYPE_INTER);                          // Motion estimation for the reference frame.             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             motionEstimation->CalculateMotionVectors(reference, residual);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Motion estimation",framesProcessedCount);             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             motionEstimation->ApplyMotionVectors(reference, residual->GetMVDisplacementsX(), residual->GetMVDisplacementsY());             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Motion compensation",framesProcessedCount);              #ifdef PIPELINE_DIAGNOSTICS             // To show a vector field representation of motion vectors             if (this->diagnosticShowVectors)             {                Logger::LogMessage("Diagnostics: Outputting motion vectors. (If nothing apppears, please use a smaller frame size.)");                external->ShowVectorField(residual->GetMVDisplacementsX(), residual->GetMVDisplacementsY(), thisFrame->GetBlockColumns(), thisFrame->GetBlockRows(), 8);             } #endif                          // Prepare a residual frame.             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             frameDifference->SubtractFrame(residual, reference);             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Frame subtraction",framesProcessedCount);             // Work out whether to code a P frame, if rate control is enabled.             PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);             bool codeP = !(rateControl->IsEnabled() && rateControl->ShouldEncodeI(residual));             PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Rate control",framesProcessedCount);             FrameDataBitLength residualLength = 0;             FrameDataBitLength intraLength = 0;                          // Transform the residual frame.             if (!rateControl->IsEnabled() || codeP)             {                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                macroblockHandler->ConvertSignedScanToSignedMacroblockLayout(residual);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Scan to macroblock layout",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dct->PictureDCT(residual);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Whole frame DCT",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dctCoefficientQuantizer->QuantizeDCTCoefficients(residual, true);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Coefficient quantization",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                residualLength = entropyEncoder->GetFrameCodedLength(residual, this->mv4);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Residual coding length only",framesProcessedCount);             }                          // Transform the intra frame.             if (!rateControl->IsEnabled() || !codeP)             {                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                macroblockHandler->ConvertScanToMacroblockLayout(thisFrame);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Scan to macroblock layout (intra)",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dct->PictureDCT(thisFrame);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Whole frame DCT (intra)",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dctCoefficientQuantizer->QuantizeDCTCoefficients(thisFrame, false);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Coefficient quantization (intra)",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                intraLength = entropyEncoder->GetFrameCodedLength(thisFrame, this->mv4);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Mode decision: Intra coding length only",framesProcessedCount);             }             // Output whichever is smaller.             if ((!rateControl->IsEnabled()) && intraLength <= residualLength || !codeP)             {                PERFORMANCE_BITS((int64_t)intraLength, "Decided intra. Bits coded", framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                this->codeFrame(thisFrame, intraLength, formatter, entropyEncoder, dctCoefficientQuantizer->GetIntraQuantizationMethod(), dctCoefficientQuantizer->GetIntraQuantizationScale(), this->mv4);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided intra. Frame coding",framesProcessedCount);                                // Compute the new reference frame.                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dctCoefficientQuantizer->DequantizeDCTCoefficients(thisFrame, false);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided intra. Dequantization for reference",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dct->PictureIDCT(thisFrame);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided intra. Whole frame IDCT for reference",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                macroblockHandler->ConvertMacroblockToScanLayout(thisFrame);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided intra. Macroblock to scan layout for reference",framesProcessedCount);                                // We no longer require the old reference. Set the reference to be this frame.                delete reference;                delete residual;                reference = thisFrame;                gopManager->Reset();                                Logger::LogMessage("I");             }             else             {                PERFORMANCE_BITS((int64_t)residualLength, "Decided inter. Bits coded", framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                this->codeFrame(residual, residualLength, formatter, entropyEncoder, dctCoefficientQuantizer->GetInterQuantizationMethod(), dctCoefficientQuantizer->GetInterQuantizationScale(), this->mv4);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided inter. Frame coding",framesProcessedCount);                // Compute the new reference frame.                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dctCoefficientQuantizer->DequantizeDCTCoefficients(residual, true);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided inter. Dequantization for reference",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                dct->PictureIDCT(residual);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided inter. Whole frame IDCT for reference",framesProcessedCount);                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                macroblockHandler->ConvertSignedMacroblockToSignedScanLayout(residual);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided inter. Macroblock to scan layout for reference",framesProcessedCount);                                // Add the reference frame. This will update reference to include the residual correction, ready for the next frame.                PERFORMANCE_TIMING_IN_LOOP_BEFORE(3);                frameDifference->AddFrame(reference, residual);                PERFORMANCE_TIMING_IN_LOOP_AFTER(3,"Decided inter. Adding residual error for reference",framesProcessedCount);                                // The intra version is no longer necessary.                delete thisFrame;                delete residual;                                Logger::LogMessage("P");                                // Increment the number of frames in this GOP.                gopManager->IncrementInterCount();             }          }                    if (this->diagnosticPerformanceTimingPerLoop)             PERFORMANCE_TIMING_AFTER(2,"Encoding time",framesProcessedCount);          // Processing of this frame is complete.          Logger::LogMessage("Processed frame %d.", framesProcessedCount);          framesProcessedCount++;       }              if (this->diagnosticPerformanceTimingGlobal)       {          PERFORMANCE_TIMING_AFTER(1,"Encoding process",0);          Logger::LogMessage("Completed performance timings:");       }              // Clean up the reference picture.       if (reference != NULL)          delete reference;              output->CloseFile();              if (this->diagnosticPerformanceBits)          PERFORMANCE_BITS(performanceStreamBits, "Total stream bits", 0);              // Display all performance data.       for (map<pair<const char*, FrameCount>, int64_t>::iterator i = performanceDetails.begin(); i != performanceDetails.end(); i++)       {          Logger::LogMessage("%s %d : %d", (i->first).first, (i->first).second, (int)i->second);       }    }        void Pipeline::decodePath(Codec* codec)    {       // The decode file to frames pipeline takes a binary file which was generated using the       // codec, decodes the file and decompresses the video to individual frames which are output.              // Retrieve configured modules from the encoder.       StreamInputModule* input = (StreamInputModule*)codec->GetModule(std::string(STREAM_INPUT_MODULE_ID));       FrameOutputModule* output = (FrameOutputModule*)codec->GetModule(std::string(FRAME_OUTPUT_MODULE_ID));       StreamParser* parser = (StreamParser*)codec->GetModule(std::string(STREAM_PARSER_MODULE_ID));       ColourSpaceConverter* yuvConverter = (ColourSpaceConverter*)codec->GetModule(std::string(COLOUR_SPACE_CONVERTER_MODULE_ID));       MacroblockHandler* macroblockHandler = (MacroblockHandler*)codec->GetModule(std::string(MACROBLOCK_HANDLER_MODULE_ID));       AANDCT* dct = (AANDCT*)codec->GetModule(std::string(AAN_DCT_MODULE_ID));       DCTCoefficientQuantizer* dctCoefficientQuantizer = (DCTCoefficientQuantizer*)codec->GetModule(std::string(DCT_COEFFICIENT_QUANTIZER_MODULE_ID));       HuffmanEntropyDecoder* entropyDecoder = (HuffmanEntropyDecoder*)codec->GetModule(std::string(HUFFMAN_ENTROPY_DECODER_MODULE_ID));       FrameDifference* frameDifference = (FrameDifference*)codec->GetModule(std::string(FRAME_DIFFERENCE_MODULE_ID));       MotionEstimation* motionEstimation = (MotionEstimation*)codec->GetModule(std::string(MOTION_ESTIMATION_MODULE_ID));              // Check that the required modules are non-NULL.       if (input == NULL || output == NULL ||          parser == NULL || yuvConverter == NULL || macroblockHandler == NULL || dct == NULL || dctCoefficientQuantizer == NULL || entropyDecoder == NULL ||          frameDifference == NULL)       {          Logger::LogMessage("One of the modules required by this pipeline was not specified. Make sure that it is enabled at the command line.");          return;       }       // Open the input stream and attach a stream parser to it.       input->OpenFile();       parser->SetInputModule(input);              // Write the file format information header.       StreamStatus* streamStatus = new StreamStatus;       parser->InputFormatHeader(streamStatus);       if (*streamStatus != STREAM_STATUS_OK)          Logger::LogMessage("Warning: The stream format identifier was incorrect. Is this the correct file type?");              StreamHeader* streamHeader = new StreamHeader;       parser->InputStreamHeader(streamStatus, streamHeader);       if (*streamStatus != STREAM_STATUS_OK)          Logger::LogMessage("Warning: The stream header information could not be read.");              // Update the 4-motion-vector state.       if (streamHeader->mv4)          motionEstimation->EnableMV4();              // Create a binary stream reader to read in the rest of the file data using       // the stream input module.       BinaryStreamReader* binaryReader = new BinaryStreamReader(input);              // Keep track of the last decoded frame so that predictive frames can be decompressed.       PictureInfo* referenceFrame = NULL;              FrameCount framesProcessedCount = 0;       while (framesProcessedCount < streamHeader->frameCount)       {          // Store the current frame as we decode it.          PictureInfo* thisFrame = new PictureInfo();                    // Get the header for this frame.          FrameHeader* frameHeader = new FrameHeader;          parser->InputFrameHeader(streamStatus, frameHeader, binaryReader);          if (*streamStatus != STREAM_STATUS_OK)             Logger::LogMessage("Warning: The frame header information could not be read.");                    // Configure based on the frame header.          if (frameHeader->pFrame)          {             thisFrame->SetFrameType(FRAME_TYPE_INTER);             Logger::LogMessage("Inter frame");          }          else          {             thisFrame->SetFrameType(FRAME_TYPE_INTRA);             Logger::LogMessage("Intra frame");          }          // The quantization method for this frame is in the frame header.          if (frameHeader->pFrame)          {             dctCoefficientQuantizer->SetInterQuantizationMethod(frameHeader->quantizationMethod);             dctCoefficientQuantizer->SetInterQuantizationScale(frameHeader->quantizationScale);          }          else          {             dctCoefficientQuantizer->SetIntraQuantizationMethod(frameHeader->quantizationMethod);             dctCoefficientQuantizer->SetIntraQuantizationScale(frameHeader->quantizationScale);          }                    // Decode this whole frame and align the reader for the next frame.          entropyDecoder->DecodeFrame(binaryReader, streamHeader, frameHeader, thisFrame);          binaryReader->AlignReader();                    // Put the frame in the spatial domain.          dctCoefficientQuantizer->DequantizeDCTCoefficients(thisFrame, thisFrame->GetFrameType() == FRAME_TYPE_INTER);          dct->PictureIDCT(thisFrame);          if (thisFrame->GetFrameType() == FRAME_TYPE_INTER)          {             // Add the just-decoded residual to the reference frame.             macroblockHandler->ConvertSignedMacroblockToSignedScanLayout(thisFrame);                          // Diagnostics section: Output residual frame data separately. #ifdef PIPELINE_DIAGNOSTICS             if (this->diagnosticOutputResiduals)             {                // Output the following frames:                // * Current reference frame (normal output previous iteration).                // * Reference with motion vectors applied.                // * Residual data added to blank image.                // * Final image (normal output).                Logger::LogMessage("Diagnostics: Outputting residual.");                PictureInfo* clonedResidual = thisFrame->Clone();                PictureInfo* referenceFrameVectorsApplied = referenceFrame->Clone();                                // Appply vectors, and make a residual image.                motionEstimation->ApplyMotionVectors(referenceFrameVectorsApplied, thisFrame->GetMVDisplacementsX(), thisFrame->GetMVDisplacementsY());                frameDifference->DiagnosticResidual(clonedResidual);                                // Convert to RGB.                yuvConverter->ConvertYUVToRGBRepresentation(referenceFrameVectorsApplied);                yuvConverter->ConvertYUVToRGBRepresentation(clonedResidual);                                // Ouput the frames.                std::stringstream withVectorsName;                std::stringstream residualName;                withVectorsName << "diagnosticsVectorsApplied" << framesProcessedCount << ".png";                residualName << "diagnosticsResidual" << framesProcessedCount << ".png";                output->WriteImage(referenceFrameVectorsApplied, withVectorsName.str());                output->WriteImage(clonedResidual, residualName.str());                                delete clonedResidual;                delete referenceFrameVectorsApplied;             } #endif                          motionEstimation->ApplyMotionVectors(referenceFrame, thisFrame->GetMVDisplacementsX(), thisFrame->GetMVDisplacementsY());             frameDifference->AddFrame(referenceFrame, thisFrame);             // Copy the byte pixel data from the reference into the current frame.             thisFrame->SetUnsignedByteData(referenceFrame->CopyUnsignedByteData(), referenceFrame->GetUnsignedByteDataLength());          }          else          {             // Store this frame as the reference frame.             macroblockHandler->ConvertMacroblockToScanLayout(thisFrame);                          // Initialize the reference if this is the first frame.             if (framesProcessedCount == 0)                referenceFrame = thisFrame->Clone();             else                referenceFrame->SetUnsignedByteData(thisFrame->CopyUnsignedByteData(), thisFrame->GetUnsignedByteDataLength());          }          // Go back to the RGB colour space.          yuvConverter->ConvertYUVToRGBRepresentation(thisFrame);                    // Write out the data.          output->WriteImage(thisFrame, framesProcessedCount);                    // Clean up the frame.          delete thisFrame;                    // Clean up meta-data.          delete frameHeader;                    // Processing of this frame is complete.          Logger::LogMessage("Processed frame %d.", framesProcessedCount);          framesProcessedCount++;       }              // Clear the reference frame.       if (referenceFrame != NULL)          delete referenceFrame;              input->CloseFile();              // Flush any cached images.       output->FlushCachedImages();              delete binaryReader;       delete streamHeader;       delete streamStatus;    }        inline int64_t Pipeline::getTime(void)    {     struct timeval tv;     gettimeofday(&tv, NULL);     return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;    } }