question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multimedia AviFil32: bug with passing AVICOMPRESSOPTIONS[] plpOptions

See original GitHub issue

There is a bug with how the AVICOMPRESSOPTIONS are passed to the AVISaveOptions, AVISaveOptionsFree and AVISaveOptionsFree functions. They are passed directly as an array of structs which causes a crash. As stated in the description, they should be passed as an array of pointers.

Pointer to an array of pointers to AVICOMPRESSOPTIONS structures. These structures hold the compression options set by the dialog box. The nStreams parameter indicates the number of pointers in the array.

I’m not sure what the most elegant way to fix this is, but I’ve confirmed that it works when the following signature is used instead:

		[DllImport("avifil32.dll")]
		public static extern unsafe bool AVISaveOptions(
			HWND hwnd, 
			ICMF_CHOOSE uiFlags, 
			int nStreams,
			[In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface, SizeParamIndex = 2)] IAVIStream[] ppavi,
			AVICOMPRESSOPTIONS** plpOptions);

And for instance a single AVICOMPRESSOPTIONS passed like this:

            AVICOMPRESSOPTIONS opts = new AVICOMPRESSOPTIONS();
            opts.fccType = streamtypeVIDEO;
            AVICOMPRESSOPTIONS* optionsPtr = &opts;
            AVICOMPRESSOPTIONS** optionsPtrPtr = &optionsPtr;
            AVISaveOptions(IntPtr.Zero, Avi.ICMF_CHOOSE.ICMF_CHOOSE_KEYFRAME | Avi.ICMF_CHOOSE.ICMF_CHOOSE_DATARATE, 1, streams, optionsPtrPtr);

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:13 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
deng0commented, Nov 11, 2021

Thanks for your work. Trying to create a small snippet, I’ve noticed that there also seem to be some other problems with your AviFil32 Wrap.

The following code sometimes creates a working video and sometimes it does not. Sadly I can’t figure out why. Perhaps you have an idea what is going on.

using Vanara.PInvoke;
using static Vanara.PInvoke.AviFil32;
using static Vanara.PInvoke.Kernel32;
using static Vanara.PInvoke.WinMm;
using static Vanara.PInvoke.Gdi32;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace WinFormsApp1
{
    internal static class Program
    {
        [STAThread]
        static unsafe void Main()
        {
            int width = 640;
            int height = 480;
            uint frameSize = (uint)(4 * width * height);

            using var bmp = new Bitmap(width, height);

            AVIFileInit();
            var result = AVIFileOpen(out var aviFile, @"c:\temp\test.avi", OpenFileAction.OF_WRITE | OpenFileAction.OF_CREATE);
            result.ThrowIfFailed();

            AVISTREAMINFO strhdr;
            strhdr.fccType = mmioStringToFOURCC("vids", 0);
            strhdr.fccHandler = mmioStringToFOURCC("CVID", 0);
            strhdr.dwFlags = 0;
            strhdr.dwCaps = 0;
            strhdr.wPriority = 0;
            strhdr.wLanguage = 0;
            strhdr.dwScale = 1;
            strhdr.dwRate = 30;
            strhdr.dwStart = 0;
            strhdr.dwLength = 0;
            strhdr.dwInitialFrames = 0;
            strhdr.dwSuggestedBufferSize = frameSize;
            strhdr.dwQuality = unchecked((uint)-1);
            strhdr.dwSampleSize = 0;
            strhdr.rcFrame.top = 0;
            strhdr.rcFrame.left = 0;
            strhdr.rcFrame.bottom = height;
            strhdr.rcFrame.right = width;
            strhdr.dwEditCount = 0;
            strhdr.dwFormatChangeCount = 0;
            strhdr.szName = string.Empty;

            result = AVIFileCreateStream(aviFile, out var aviStream, in strhdr);
            result.ThrowIfFailed();

            IAVIStream[] aviStreams = new IAVIStream[1] { aviStream };


            // bugged version
            //AVICOMPRESSOPTIONS[] options = new AVICOMPRESSOPTIONS[1];
            //options[0].fccType = streamtypeVIDEO;
            //AVISaveOptions(IntPtr.Zero, ICMF_CHOOSE.ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE.ICMF_CHOOSE_DATARATE, 1, aviStreams, options);
            //AVISaveOptionsFree(1, options);
            //result = AVIMakeCompressedStream(out var compressedStream, aviStream, in options[0]);

            // fixed version                
            AVICOMPRESSOPTIONS options = new AVICOMPRESSOPTIONS();
            options.fccType = streamtypeVIDEO;
            AVICOMPRESSOPTIONS* optionsPtr = &options;
            AVICOMPRESSOPTIONS** optionsPtrPtr = &optionsPtr;

            [DllImport("avifil32.dll")]
            static extern unsafe bool AVISaveOptions(
                HWND hwnd,
                ICMF_CHOOSE uiFlags,
                int nStreams,
                [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface, SizeParamIndex = 2)] IAVIStream[] ppavi,
                AVICOMPRESSOPTIONS** plpOptions);

            [DllImport("avifil32.dll", ExactSpelling = true)]
            static extern HRESULT AVISaveOptionsFree(int nStreams, AVICOMPRESSOPTIONS** plpOptions);

            AVISaveOptions(IntPtr.Zero, ICMF_CHOOSE.ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE.ICMF_CHOOSE_DATARATE, 1, aviStreams, optionsPtrPtr);
            AVISaveOptionsFree(1, optionsPtrPtr);
            result = AVIMakeCompressedStream(out var compressedStream, aviStream, in options);


            result.ThrowIfFailed();

            BITMAPINFOHEADER bi = new BITMAPINFOHEADER();
            bi.biSize = (uint)Marshal.SizeOf(bi);
            bi.biWidth = width;
            bi.biHeight = height;
            bi.biPlanes = 1;
            bi.biBitCount = 32;
            bi.biSizeImage = frameSize;

            result = AVIStreamSetFormat(compressedStream, 0, new IntPtr(&bi), (int)bi.biSize);
            result.ThrowIfFailed();

            for (int i = 0; i < 200; i++)
            {
                using (var graphics = Graphics.FromImage(bmp))
                {
                    graphics.Clear(Color.FromArgb(Random.Shared.Next()));
                }

                BitmapData bmpData = bmp.LockBits(
                    new Rectangle(0, 0, bmp.Width, bmp.Height),
                    ImageLockMode.ReadOnly, bmp.PixelFormat);

                try
                {
                    result = AVIStreamWrite(
                        compressedStream,
                        i,
                        1,
                        bmpData.Scan0,
                        bmpData.Stride * bmpData.Height,
                        0, out _, out _);
                    result.ThrowIfFailed();
                }
                finally
                {
                    bmp.UnlockBits(bmpData);
                }
            }

            AVIStreamRelease(compressedStream);
            AVIStreamRelease(aviStream);

            AVIFileRelease(aviFile);
            AVIFileExit();
        }
    }
}

To be honest I’ve just stumbled upon your library, because I ported an old program to .NET 6.0 and had a problem with my old AviFil32 wrap. I’ve managed to solve that problem and will probably stick to my old wrap. In the long run I want to replace AviFil32 all together with a more modern alternative.

0reactions
deng0commented, Nov 15, 2021

OK, I see. Thanks.

Read more comments on GitHub >

github_iconTop Results From Across the Web

AVICOMPRESSOPTIONS structure (vfw.h) - Win32
This structure passes data to the AVIMakeCompressedStream function (or the AVISave function, which uses AVIMakeCompressedStream). Syntax. C++
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found