private void EncodePredictedFrame(Stream outStream, BitmapData inputData, BitmapData previousData, int pixelBytes) { outStream.WriteByte((byte)FrameType.Predicted); int xBlocksCount = DivideRoundUp(frameWidth, MCBlockSize); int yBlocksCount = DivideRoundUp(frameHeight, MCBlockSize); int identicalBlocksCount = 0; int translatedBlocksCount = 0; int fullBlocksCount = 0; for (int yBlock = 0; yBlock < yBlocksCount; yBlock++) { for (int xBlock = 0; xBlock < xBlocksCount; xBlock++) { // absolute position of the block start int yStart = yBlock * MCBlockSize; int xStart = xBlock * MCBlockSize; MotionVector motionVector; bool motionVectorFound = SearchMotionVector(inputData, previousData, pixelBytes, yStart, xStart, out motionVector); if (motionVectorFound) { if ((motionVector.x == 0) && (motionVector.y == 0)) { outStream.WriteByte((byte)MCRecordType.Identical); identicalBlocksCount++; } else { // store a record type being a motion vector outStream.WriteByte((byte)MCRecordType.MotionVector); // store the motion vector itself // TODO: store only a difference to the previous motion vector // TODO: it could be possible to store only an index to the vector of // possible motion vectors outStream.WriteSShort(motionVector.x); outStream.WriteSShort(motionVector.y); translatedBlocksCount++; } } else { // store a record type being a full block outStream.WriteByte((byte)MCRecordType.FullBlock); // store the full block contents EncodeFullBlock(outStream, inputData, previousData, pixelBytes, yStart, xStart); fullBlocksCount++; } } } Log("Block counts - identical: {0}, translated: {1}, full: {2}", identicalBlocksCount, translatedBlocksCount, fullBlocksCount); }
public void EncodeFrame(int frameIndex, Bitmap inputFrame, Stream outStream) { if ((inputFrame == null) || (outStream == null)) return; int width = inputFrame.Width; int height = inputFrame.Height; if ((width != frameWidth) || (height != frameHeight)) return; // frame header: [ MAGIC_FRAME, frameIndex, frameType ] outStream.WriteUInt(MAGIC_FRAME); outStream.WriteSShort((short)frameIndex); BitmapData inputData = inputFrame.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, inputFrame.PixelFormat); BitmapData previousData = previousFrame.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, previousFrame.PixelFormat); int pixelBytes = GetBytesPerPixel(inputFrame.PixelFormat); if ((frameIndex % IntraFrameFrequency) == 0) { EncodeIntraFrame(outStream, inputData, pixelBytes); } else { EncodePredictedFrame(outStream, inputData, previousData, pixelBytes); } inputFrame.UnlockBits(inputData); previousFrame.UnlockBits(previousData); previousFrame.Dispose(); previousFrame = inputFrame; }