Directshow & .Net - Bitmap showing stripe to the right of the left side of the image?

Image example: alt text

I am using DirectShow.net to get webcam footage in my program. To do this, I add the source camera to the graphics and VideoMixingRenderer9.

This part works smoothly, but the part where I fetch the frame using GetCurrentImage (from lpDib) has what I can only describe as an odd problem.

I am using Marshal.PtrToSTructure to create BitmapInfoHeader from lpDib and then calculate width / height / stride / and pixel format.

The problem occurs when I look at an image stored in a bitmap. It is 10px wide on the left, which comes from what is actually correct!

It's worth noting that the data I receive from the GetCurrentImage call is actually reversed - note the call to Cap.RotateFlip.

IntPtr lpDib;
windowlessCtrl.GetCurrentImage(out lpDib);

BitmapInfoHeader head;
head = (BitmapInfoHeader)Marshal.PtrToStructure(lpDib, typeof(BitmapInfoHeader));
int width = head.Width;
int height = head.Height;
int stride = width * (head.BitCount / 8);
PixelFormat pixelFormat = PixelFormat.Format24bppRgb;

switch (head.BitCount)
{
    case 24: pixelFormat = PixelFormat.Format24bppRgb; break;
    case 32: pixelFormat = PixelFormat.Format32bppRgb; break;
    case 48: pixelFormat = PixelFormat.Format48bppRgb; break;
    default: throw new Exception("Unknown BitCount");
}

Cap = new Bitmap(width, height, stride, pixelFormat, lpDib);
Cap.RotateFlip(RotateFlipType.RotateNoneFlipY);
//if we examine Cap here (Cap.Save, for example) I'm seeing the odd stripe.

      

I am completely lost here. It seems to be something like an offset problem and I tried adjusting with steps some but to no avail (just creates an odd diagonal view).

+2


source to share


3 answers


The video renderer expands the bitmap according to its memory alignment needs, but it will adjust the media type to fit. The VIDEOINFOHEADER (or VIDEOINFOHEADER2) structure in the media type will have an rcTarget rectangle that defines the allowed area in the larger bitmap. You can query the current media type on the input pin and get this information.

You will find that the rendering only needs this advanced step for some formats, so perhaps your simplest approach is to force a different capture format. An alternative is to use a sample capture filter instead of VMR.



FROM

+1


source


This code is generated using DirectShowLib samples and it works:



public Bitmap GetCurrentImage()
        {
            Bitmap bmp = null;
            if (windowlessCtrl != null)
            {
                IntPtr currentImage = IntPtr.Zero;

                try
                {
                    int hr = windowlessCtrl.GetCurrentImage(out currentImage);
                    DsError.ThrowExceptionForHR(hr);

                    if (currentImage != IntPtr.Zero)
                    {
                        BitmapInfoHeader structure = new BitmapInfoHeader();
                        Marshal.PtrToStructure(currentImage, structure);

                        PixelFormat pixelFormat = PixelFormat.Format24bppRgb;
                        switch (structure.BitCount)
                        {
                            case 24:
                                pixelFormat = PixelFormat.Format24bppRgb;
                                break;
                            case 32:
                                pixelFormat = PixelFormat.Format32bppRgb;
                                break;
                            case 48:
                                pixelFormat = PixelFormat.Format48bppRgb;
                                break;
                            default:
                                throw new Exception("BitCount desconhecido");
                        }

                        // este trecho: new IntPtr(currentImage.ToInt64() + 40), é o que resolve o problema da faixa (strip) da direita na esquerda.
                        bmp = new Bitmap(structure.Width, structure.Height, (structure.BitCount / 8) * structure.Width, pixelFormat, new IntPtr(currentImage.ToInt64() + 40));
                        bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    }
                }
                catch (Exception anyException)
                {
                    MessageBox.Show("Falha gravando imagem da Webcam: " + anyException.ToString());
                }
                finally
                {
                    Marshal.FreeCoTaskMem(currentImage);
                }
            }
            return bmp;
        }

      

+2


source


For those who want to avoid using SampleGrabber. The stripe problem can be corrected by adding a bitmap header offset to the IntPtr. However, this requires unsafe code

    IntPtr pBuffer = IntPtr.Zero;
    int xBufferSize = 0;
    int xWidth, xHeight;

    basicVideo.get_VideoWidth(out xWidth);
    basicVideo.get_VideoHeight(out xHeight);

    int hr = basicVideo.GetCurrentImage(ref xBufferSize, IntPtr.Zero);
    pBuffer = Marshal.AllocCoTaskMem(xBufferSize);

    // Get the pixel buffer for the thumbnail
    hr = basicVideo.GetCurrentImage(ref xBufferSize, pBuffer);

    // Offset for BitmapHeader info
    var bitmapHeader = (BitmapInfoHeader)Marshal.PtrToStructure(pBuffer, typeof(BitmapInfoHeader));
    var pBitmapData = (byte*)pBuffer.ToPointer();
    pBitmapData += bitmapHeader.Size;

    // This will be the pointer to the bitmap pixels
    var bitmapData = new IntPtr(pBitmapData);

    //Change for your format type!
    System.Drawing.Imaging.PixelFormat xFormat = (System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    int bitsPerPixel = ((int)xFormat & 0xff00) >> 8;
    int bytesPerPixel = (bitsPerPixel + 7) / 8;
    int stride = 4 * ((xWidth * bytesPerPixel + 3) / 4);

    Bitmap image = new Bitmap(xWidth, xHeight, stride, xFormat, bitmapData);
    image.RotateFlip(RotateFlipType.RotateNoneFlipY);
    return image;

      

The calculation for the Stride can be found here .

0


source







All Articles