private void DecodePredictedFrame(Stream inStream, BitmapData currentData, BitmapData previousData, int pixelBytes) { int xBlocksCount = DivideRoundUp(frameWidth, MCBlockSize); int yBlocksCount = DivideRoundUp(frameHeight, MCBlockSize); MotionVector motionVector = MotionVector.ZERO; for (int yBlock = 0; yBlock < yBlocksCount; yBlock++) { for (int xBlock = 0; xBlock < xBlocksCount; xBlock++) { int yStart = yBlock * MCBlockSize; int xStart = xBlock * MCBlockSize; // TODO: handle bad value MCRecordType mcType = (MCRecordType)inStream.ReadUByte(); switch (mcType) { case MCRecordType.Identical: DecodeTranslatedBlock(inStream, currentData, previousData, pixelBytes, yStart, xStart, MotionVector.ZERO); break; case MCRecordType.MotionVector: motionVector.x = inStream.ReadSShort(); motionVector.y = inStream.ReadSShort(); DecodeTranslatedBlock(inStream, currentData, previousData, pixelBytes, yStart, xStart, motionVector); break; case MCRecordType.FullBlock: DecodeFullBlock(inStream, currentData, previousData, pixelBytes, yStart, xStart); break; } } } }
public Bitmap DecodeFrame(int frameIndex, Stream inStream) { if (inStream == null) return null; try { // Check the frame header: if (inStream.ReadUInt() != MAGIC_FRAME) return null; int encodedFrameIndex = inStream.ReadSShort(); if (encodedFrameIndex != frameIndex) return null; BitmapData currentData = currentFrame.LockBits( new Rectangle(0, 0, frameWidth, frameHeight), ImageLockMode.ReadOnly, currentFrame.PixelFormat); BitmapData previousData = previousFrame.LockBits( new Rectangle(0, 0, frameWidth, frameHeight), ImageLockMode.ReadOnly, previousFrame.PixelFormat); if (VisualizeMCBlockTypes) { debugFrame = new Bitmap(frameWidth, frameHeight, PixelFormat.Format24bppRgb); debugFrameData = debugFrame.LockBits( new Rectangle(0, 0, frameWidth, frameHeight), ImageLockMode.ReadOnly, debugFrame.PixelFormat); } int pixelBytes = GetBytesPerPixel(currentFrame.PixelFormat); // TODO: handle bad value FrameType frameType = (FrameType)inStream.ReadUByte(); switch (frameType) { case FrameType.Intra: DecodeIntraFrame(inStream, currentData, pixelBytes); break; case FrameType.Predicted: DecodePredictedFrame(inStream, currentData, previousData, pixelBytes); break; } currentFrame.UnlockBits(currentData); previousFrame.UnlockBits(previousData); if (VisualizeMCBlockTypes) { debugFrame.UnlockBits(debugFrameData); debugFrame.Save(String.Format("debug{0:000000}.png", frameIndex), ImageFormat.Png); debugFrame.Dispose(); } } catch (EndOfStreamException ex) { Log("Exception: {0} {1}", ex.Message, ex.StackTrace); return null; } Bitmap result = currentFrame; // double buffering // save the current bitmap to act as previous one when decoding the next frame SwapBitmaps(ref previousFrame, ref currentFrame); //currentFrame.Dispose(); return result; }