Google

Mogre to AVI (without external dependencies)

Discussion regarding the Managed .Net Wrapper for Ogre, MOGRE (http://sourceforge.net/projects/mogre)

Moderators: OGRE Team, MOGRE Moderators

Mogre to AVI (without external dependencies)

Postby nataz » Mon Aug 13, 2007 8:44 am

Hi all,

during the development of one of my Projects i needed to Render to AVI. There was a Post about this, but 1st: the Files are not valid, 2nd: it was not multithreaded, so the Rendering of the Main app slowed incredibly down.

Here is my approach, please note, that i had just a few quick tests and cant guarantee anything, use at your own risk:

AviWriter.cs
Code: Select all
/* Author: Daniel Koppers
 * Date  : 13.09.2007
 * Desc  : A Class to Wrap the Win32 AVI Functions into C# and provide a reliable AVI Writer.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace VirtualStudio
{
    class AviWrite
    {
        #region AVI STRUCTS

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct RECT
        {
            public UInt32 left;
            public UInt32 top;
            public UInt32 right;
            public UInt32 bottom;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct BITMAPINFOHEADER
        {
            public UInt32 biSize;
            public Int32 biWidth;
            public Int32 biHeight;
            public Int16 biPlanes;
            public Int16 biBitCount;
            public UInt32 biCompression;
            public UInt32 biSizeImage;
            public Int32 biXPelsPerMeter;
            public Int32 biYPelsPerMeter;
            public UInt32 biClrUsed;
            public UInt32 biClrImportant;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct AVISTREAMINFO
        {
            public UInt32 fccType;
            public UInt32 fccHandler;
            public UInt32 dwFlags;
            public UInt32 dwCaps;
            public UInt16 wPriority;
            public UInt16 wLanguage;
            public UInt32 dwScale;
            public UInt32 dwRate;
            public UInt32 dwStart;
            public UInt32 dwLength;
            public UInt32 dwInitialFrames;
            public UInt32 dwSuggestedBufferSize;
            public UInt32 dwQuality;
            public UInt32 dwSampleSize;
            public RECT rcFrame;
            public UInt32 dwEditCount;
            public UInt32 dwFormatChangeCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public UInt16[] szName;
        }
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        private struct BITMAPFILEHEADER
        {
            public Int16 bfType; //"magic cookie" - must be "BM"
            public Int32 bfSize;
            public Int16 bfReserved1;
            public Int16 bfReserved2;
            public Int32 bfOffBits;
        }

        #endregion
        #region WIN32 NATIVE IMPORTS
        // Lib init
        [DllImport("avifil32.dll")]
        private static extern void AVIFileInit();

        //Open an AVI file
        [DllImport("avifil32.dll", PreserveSig = true)]
        private static extern int AVIFileOpen(
            ref int ppfile,
            String szFile,
            int uMode,
            int pclsidHandler);

        //Get a stream from an open AVI file
        [DllImport("avifil32.dll")]
        private static extern int AVIFileGetStream(
            int pfile,
            out IntPtr ppavi,
            int fccType,
            int lParam);

        //Release an open AVI stream
        [DllImport("avifil32.dll")]
        private static extern int AVIStreamRelease(IntPtr aviStream);

        //Release an ope AVI file
        [DllImport("avifil32.dll")]
        public static extern int AVIFileRelease(int pfile);

        //Close the AVI library
        [DllImport("avifil32.dll")]
        private static extern void AVIFileExit();

        //Create a new stream in an open AVI file
        [DllImport("avifil32.dll")]
        private static extern int AVIFileCreateStream(
            int pfile,
            out IntPtr ppavi,
            ref AVISTREAMINFO ptr_streaminfo);

        //Set the format for a new stream
        [DllImport("avifil32.dll")]
        private static extern int AVIStreamSetFormat(
            IntPtr aviStream, Int32 lPos,
            ref BITMAPINFOHEADER lpFormat, Int32 cbFormat);

        //Write a sample to a stream
        [DllImport("avifil32.dll")]
        private static extern int AVIStreamWrite(
            IntPtr aviStream, Int32 lStart, Int32 lSamples,
            IntPtr lpBuffer, Int32 cbBuffer, Int32 dwFlags,
            Int32 dummy1, Int32 dummy2);
        #endregion
        private int aviFile = 0;
        private IntPtr aviStream = IntPtr.Zero;
        private BackgroundWorker bgw;
        private List<Bitmap> lstBmp;
        private bool die = false;
        public AviWrite(string FileName, int FrameRate, int Height, int Width, int Stride)
        {
            // Init the AVI Lib and open up the File
            AVIFileInit();

            int hr = AVIFileOpen(ref aviFile, FileName, 4097, 0); // 4097 should be the int bitmask for WRITE/CREATE

            AVISTREAMINFO streaminfo = new AVISTREAMINFO();
            streaminfo.fccType = 1935960438; // Video Type
            streaminfo.fccHandler = 1668707181; // MS Video v1
            streaminfo.dwScale = 1;
            streaminfo.dwRate = (uint)FrameRate;
            streaminfo.dwSuggestedBufferSize = (UInt32)(Height * Stride);
            streaminfo.dwQuality = 10000; // We`ll assume that we use non compressed with highest quality
                                          // else we would probably see aliasing or artifacts
            streaminfo.rcFrame.bottom = (UInt32)Height;
            streaminfo.rcFrame.right = (UInt32)Width;
            streaminfo.szName = new UInt16[64];

            // Create a Stream now
            int res = AVIFileCreateStream(aviFile, out aviStream, ref streaminfo);

            // Now we go ahead and create the image format header
            BITMAPINFOHEADER binfo = new BITMAPINFOHEADER();
            binfo.biSize = (UInt32)Marshal.SizeOf(binfo);
            binfo.biWidth = (Int32)Width;
            binfo.biHeight = (Int32)Height;
            binfo.biPlanes = 1;
            binfo.biBitCount = 24;
            binfo.biSizeImage = (UInt32)(Stride * Height);

            // and push in a stream
            res = AVIStreamSetFormat(aviStream, 0, ref binfo, Marshal.SizeOf(binfo));

            // We will use a Thread to write the AVI Data into the File...
            bgw = new BackgroundWorker();
            bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
            lstBmp = new List<Bitmap>(); // We will add bmp`s here for the Thread to add
            bgw.RunWorkerAsync();
        }

        void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            int countFrames = 0;
            while (!die)
            {
                while(lstBmp.Count > 0)
                {
                    Bitmap tmpBmp;
                    lock(lstBmp)
                    {
                        tmpBmp = lstBmp[0];
                        lstBmp.RemoveAt(0);
                    }

                    // We need to rotate and flip the image...
                    tmpBmp.RotateFlip(RotateFlipType.Rotate180FlipX);
                    BitmapData bmpDat = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height),ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                    int result = AVIStreamWrite(aviStream, countFrames, 1, bmpDat.Scan0, (Int32)(bmpDat.Stride * bmpDat.Height), 0, 0, 0);
                    tmpBmp.UnlockBits(bmpDat);
                    countFrames++;
                    //MessageBox.Show("Added AVI!");
                }
            }
        }

        public void AviAddFrame(Bitmap bmp)
        {
            if(!die)
                lstBmp.Add(bmp);
        }

        public void EndAvi()
        {
            die = true;
            while (bgw.IsBusy) ;
            AVIStreamRelease(aviStream);
            AVIFileRelease(aviFile);
            AVIFileExit();
        }
    }
}


Note: Some parts are taken from a Codeproject Article, and i do not claim that these are my own work...

Usage:

Get a RTT Target up and Running and do the Following:

Code: Select all
texturePtr.GetBuffer().BlitToMemory(pb);
                            bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
                            Marshal.Copy(bytes, 0, bmpData.Scan0, (int)buffer.SizeInBytes);
                            bmp.UnlockBits(bmpData);
                            if (aw == null)
                                aw = new VirtualStudio.AviWrite(aviFileName, 25, bmp.Height, bmp.Width, bmpData.Stride);
                            aw.AviAddFrame(bmp);


Now do aw.AviAddFrame(bmp); each frame.

To end a AviFile propperly do:

Code: Select all
aw.EndAvi();


Note that you, in order to get a Propper AVI File, have to stabilize your Framerate to the framerate used in the Constructor, else the AVI may become async etc.

Have fun with it... nataz
nataz
Kobold
 
Posts: 35
Kudos: 0
Joined: 24 Jul 2007

Postby smernesto » Mon Aug 13, 2007 9:43 pm

Do you have the link to the codeproject article?.

If you want I can put your code in the wiki.

Ernesto
User avatar
smernesto
Greenskin
 
Posts: 143
Kudos: 1
Joined: 18 Nov 2006
Location: Bogota, Colombia

Postby nataz » Tue Aug 14, 2007 5:32 am

If you want fell free to do so. Cant recall the link right now sorry
nataz
Kobold
 
Posts: 35
Kudos: 0
Joined: 24 Jul 2007

Postby smernesto » Tue Aug 14, 2007 6:34 am

Don´t worry , I will search codeproject.
User avatar
smernesto
Greenskin
 
Posts: 143
Kudos: 1
Joined: 18 Nov 2006
Location: Bogota, Colombia


Return to MOGRE

Who is online

Users browsing this forum: Bing [Bot] and 0 guests

cron